1
1
import os
2
2
import io
3
+ import math
4
+ from decimal import Decimal
3
5
4
6
GMT_ROOT_DIR = os .path .dirname (os .path .abspath (__file__ ))+ '/../../'
5
7
@@ -278,8 +280,124 @@ def test_phase_stats_single_network_procfs():
278
280
assert data [14 ]['sampling_rate_95p' ] == 100477 , '95p sampling rate not in expected range'
279
281
assert isinstance (data [14 ]['sampling_rate_95p' ], int )
280
282
281
-
282
- def test_sci ():
283
+ def test_phase_stats_network_data ():
284
+ run_id = Tests .insert_run ()
285
+ Tests .import_network_io_cgroup_container (run_id )
286
+
287
+ test_sci_config = {
288
+ 'N' : 0.001 , # Network energy intensity (kWh/GB)
289
+ 'I' : 500 , # Carbon intensity (gCO2e/kWh)
290
+ }
291
+
292
+ build_and_store_phase_stats (run_id , sci = test_sci_config )
293
+
294
+ # Network energy data
295
+ network_energy_data = DB ().fetch_all (
296
+ 'SELECT metric, detail_name, unit, value, type, phase FROM phase_stats WHERE phase = %s AND metric = %s' ,
297
+ params = ('004_[RUNTIME]' , 'network_energy_formula_global' ), fetch_mode = 'dict'
298
+ )
299
+
300
+ assert len (network_energy_data ) == 1 , f"Expected 1 network energy formula entry, got { len (network_energy_data )} "
301
+
302
+ network_energy_entry = network_energy_data [0 ]
303
+ assert network_energy_entry ['metric' ] == 'network_energy_formula_global'
304
+ assert network_energy_entry ['detail_name' ] == '[FORMULA]'
305
+ assert network_energy_entry ['unit' ] == 'uJ'
306
+ assert network_energy_entry ['type' ] == 'TOTAL'
307
+ assert network_energy_entry ['phase' ] == '004_[RUNTIME]'
308
+
309
+ network_totals = DB ().fetch_all (
310
+ 'SELECT detail_name, value FROM phase_stats WHERE phase = %s AND metric = %s' ,
311
+ params = ('004_[RUNTIME]' , 'network_total_cgroup_container' ), fetch_mode = 'dict'
312
+ )
313
+ total_network_bytes = sum (row ['value' ] for row in network_totals )
314
+ expected_network_energy_kwh = Decimal (total_network_bytes ) / 1_000_000_000 * Decimal (test_sci_config ['N' ])
315
+ expected_network_energy_uj = expected_network_energy_kwh * 3_600_000_000_000
316
+ assert math .isclose (network_energy_entry ['value' ], expected_network_energy_uj , rel_tol = 1e-5 ), f"Expected network energy: { expected_network_energy_uj } , got: { network_energy_entry ['value' ]} "
317
+
318
+ # Network carbon data
319
+ network_carbon_data = DB ().fetch_all (
320
+ 'SELECT metric, detail_name, unit, value, type FROM phase_stats WHERE phase = %s AND metric = %s' ,
321
+ params = ('004_[RUNTIME]' , 'network_carbon_formula_global' ), fetch_mode = 'dict'
322
+ )
323
+
324
+ assert len (network_carbon_data ) == 1 , "Expected 1 network carbon formula entry"
325
+
326
+ network_carbon_entry = network_carbon_data [0 ]
327
+ expected_network_carbon_ug = expected_network_energy_kwh * Decimal (test_sci_config ['I' ]) * 1_000_000
328
+
329
+ assert network_carbon_entry ['metric' ] == 'network_carbon_formula_global'
330
+ assert network_carbon_entry ['detail_name' ] == '[FORMULA]'
331
+ assert network_carbon_entry ['unit' ] == 'ug'
332
+ assert network_carbon_entry ['type' ] == 'TOTAL'
333
+ assert math .isclose (network_carbon_entry ['value' ], expected_network_carbon_ug , rel_tol = 1e-5 ), f"Expected network carbon: { expected_network_carbon_ug } , got: { network_carbon_entry ['value' ]} "
334
+
335
+ def test_sci_calculation ():
336
+ run_id = Tests .insert_run ()
337
+ Tests .import_machine_energy (run_id ) # Machine energy component
338
+ Tests .import_network_io_cgroup_container (run_id ) # Network component (custom N parameter)
339
+
340
+ # Define comprehensive SCI configuration with all required parameters
341
+ test_sci_config = {
342
+ 'N' : 0.001 , # Network energy intensity (kWh/GB)
343
+ 'I' : 500 , # Carbon intensity (gCO2e/kWh)
344
+ 'EL' : 4 , # Expected lifespan (years)
345
+ 'TE' : 300000 , # Total embodied emissions (gCO2e)
346
+ 'RS' : 1 , # Resource share (100%)
347
+ 'R' : 10 , # Functional unit count (10 runs)
348
+ 'R_d' : 'test runs' # Functional unit description
349
+ }
350
+
351
+ build_and_store_phase_stats (run_id , sci = test_sci_config )
352
+
353
+ # Verify all SCI components are calculated and stored correctly
354
+
355
+ # 1. Machine carbon from energy consumption
356
+ machine_carbon_data = DB ().fetch_all (
357
+ 'SELECT metric, value, unit FROM phase_stats WHERE phase = %s AND metric = %s' ,
358
+ params = ('004_[RUNTIME]' , 'psu_carbon_ac_mcp_machine' ), fetch_mode = 'dict'
359
+ )
360
+ assert len (machine_carbon_data ) == 1 , "Machine carbon should be calculated"
361
+ machine_carbon_ug = machine_carbon_data [0 ]['value' ]
362
+
363
+ # 2. Embodied carbon calculation
364
+ embodied_carbon_data = DB ().fetch_all (
365
+ 'SELECT metric, value, unit FROM phase_stats WHERE phase = %s AND metric = %s' ,
366
+ params = ('004_[RUNTIME]' , 'embodied_carbon_share_machine' ), fetch_mode = 'dict'
367
+ )
368
+ assert len (embodied_carbon_data ) == 1 , "Embodied carbon should be calculated"
369
+ embodied_carbon_ug = embodied_carbon_data [0 ]['value' ]
370
+
371
+ # 3. Network carbon calculation
372
+ network_carbon_data = DB ().fetch_all (
373
+ 'SELECT metric, value, unit FROM phase_stats WHERE phase = %s AND metric = %s' ,
374
+ params = ('004_[RUNTIME]' , 'network_carbon_formula_global' ), fetch_mode = 'dict'
375
+ )
376
+ assert len (network_carbon_data ) == 1 , "Network carbon should be calculated"
377
+ network_carbon_ug = network_carbon_data [0 ]['value' ]
378
+
379
+ # 4. Final SCI calculation verification
380
+ sci_data = DB ().fetch_all (
381
+ 'SELECT value, unit FROM phase_stats WHERE phase = %s AND metric = %s' ,
382
+ params = ('004_[RUNTIME]' , 'software_carbon_intensity_global' ), fetch_mode = 'dict'
383
+ )
384
+ assert len (sci_data ) == 1 , "SCI should be calculated for the whole run"
385
+ sci_entry = sci_data [0 ]
386
+
387
+ # Verify SCI unit format includes functional unit description - fail if other unit occurs
388
+ expected_unit = f"ugCO2e/{ test_sci_config ['R_d' ]} "
389
+ assert sci_entry ['unit' ] == expected_unit , \
390
+ f"Test fails: Unexpected unit detected. Expected: { expected_unit } , got: { sci_entry ['unit' ]} . This test is designed to fail when incorrect units are present."
391
+
392
+ # Verify SCI value matches expected value: (machine_carbon + embodied_carbon + network_carbon) / R
393
+ expected_sci_value = (machine_carbon_ug + embodied_carbon_ug + network_carbon_ug ) / Decimal (test_sci_config ['R' ])
394
+ assert math .isclose (abs (sci_entry ['value' ]), expected_sci_value , rel_tol = 1e-5 ), f"SCI calculation should be correct. Expected: { expected_sci_value } , got: { sci_entry ['value' ]} "
395
+
396
+ # Verify SCI value is reasonable (positive and within expected range)
397
+ assert sci_entry ['value' ] > 0 , "SCI should be positive"
398
+ assert sci_entry ['value' ] < 1000000 , "SCI should be reasonable (less than 1M ugCO2e per functional unit)"
399
+
400
+ def test_sci_run ():
283
401
runner = ScenarioRunner (uri = GMT_ROOT_DIR , uri_type = 'folder' , filename = 'tests/data/usage_scenarios/stress_sci.yml' , skip_system_checks = True , dev_cache_build = True , dev_no_sleeps = True , dev_no_metrics = False , dev_no_phase_stats = False )
284
402
285
403
out = io .StringIO ()
@@ -289,7 +407,6 @@ def test_sci():
289
407
290
408
data = DB ().fetch_all ("SELECT value, unit FROM phase_stats WHERE phase = %s AND run_id = %s AND metric = 'software_carbon_intensity_global' " , params = ('004_[RUNTIME]' , run_id ), fetch_mode = 'dict' )
291
409
292
-
293
410
assert len (data ) == 1
294
411
assert 50 < data [0 ]['value' ] < 150
295
412
assert data [0 ]['unit' ] == 'ugCO2e/Cool run'
0 commit comments