Skip to content

Commit f40d4af

Browse files
committed
Refactor: Added task_id & status to emission metrics
Refactor: Renamed emission metrics to camel case Test: Adjusted tests to new naming Signed-off-by: Josua Carl <josua.carl@uni-tuebingen.de>
1 parent fd48147 commit f40d4af

23 files changed

Lines changed: 175 additions & 192 deletions

docs/assets/co2footprint_report_sample.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/main/nextflow/co2footprint/CO2FootprintObserver.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ class CO2FootprintObserver implements TraceObserver {
220220
workflowStats.summarize()
221221

222222
log.info(
223-
"🌱 The workflow run used ${workflowStats.co2Record.toReadable('energy')} of electricity, " +
223+
"🌱 The workflow run used ${workflowStats.co2Record.toReadable('energy_consumption')} of electricity, " +
224224
"resulting in the release of ${workflowStats.co2Record.toReadable('CO2e')} of CO₂ equivalents into the atmosphere."
225225
)
226226
}

src/main/nextflow/co2footprint/FileCreation/ReportFileCreator.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,13 @@ class ReportFileCreator extends BaseFileCreator{
186186

187187
// Retrieve total CO₂ emissions and energy consumption for the given suffix
188188
Double co2e = workflowRecord.get("CO2e${suffix}") as Double
189-
Double energy = workflowRecord.get("energy${suffix}") as Double
189+
Double energy = workflowRecord.get("energy_consumption${suffix}") as Double
190190

191191
if (co2e != null) {
192192
CO2EquivalencesRecord equivalences = co2FootprintComputer.computeCO2footprintEquivalences(co2e)
193193
return [
194194
("CO2e${suffix}" as String): new Quantity(co2e,'', 'g').toReadable(),
195-
("energy${suffix}" as String): new Quantity(energy,'k','Wh').toReadable(),
195+
("energy_consumption${suffix}" as String): new Quantity(energy,'k','Wh').toReadable(),
196196
("car${suffix}" as String): equivalences.getCarKilometersReadable(),
197197
("tree${suffix}" as String): equivalences.getTreeMonthsReadable(),
198198
("plane_percent${suffix}" as String): equivalences.getPlanePercent() < 100.0 ? equivalences.getPlanePercentReadable() : null,
@@ -237,7 +237,7 @@ class ReportFileCreator extends BaseFileCreator{
237237
*/
238238
protected Map<String, Object> collectSummary(CO2RecordTree stats=this.stats) {
239239
// Add an empty map if the process is not already present
240-
return stats.collectByLevel('process', ['CO2e', 'energy', 'CO2e_non_cached', 'energy_non_cached'])
240+
return stats.collectByLevel('process', ['CO2e', 'energy_consumption', 'CO2e_non_cached', 'energy_consumption_non_cached'])
241241
}
242242

243243

src/main/nextflow/co2footprint/FileCreation/SummaryFileCreator.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class SummaryFileCreator extends BaseFileCreator {
5050
/**
5151
* Write the summary file with totals and options.
5252
*
53-
* @param totalStats Map containing total energy ('energy') in Wh and total CO₂ emissions ('CO2e') in grams.
53+
* @param totalStats Map containing total energy ('energy_consumption') in Wh and total CO₂ emissions ('CO2e') in grams.
5454
* @param co2FootprintComputer CO2FootprintCalculator instance for calculating equivalences.
5555
* @param config CO2FootprintConfig instance with plugin configuration.
5656
*/
@@ -66,7 +66,7 @@ class SummaryFileCreator extends BaseFileCreator {
6666
String outText = """\
6767
Total CO₂e footprint measures of this workflow run (including cached tasks):
6868
CO₂e emissions: ${new Quantity(totalStats['CO2e'],'', 'g').round().toReadable() }
69-
Energy consumption: ${new Quantity(totalStats['energy'], 'k', 'Wh').toReadable() }
69+
Energy consumption: ${new Quantity(totalStats['energy_consumption'], 'k', 'Wh').toReadable() }
7070
CO₂e emissions (market): ${totalStats['CO2e_market'] ? new Quantity(totalStats['CO2e_market'], '', 'g').toReadable() : "-"}
7171
7272
""".stripIndent()

src/main/nextflow/co2footprint/FileCreation/TraceFileCreator.groovy

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,6 @@ class TraceFileCreator extends BaseFileCreator {
2020
// Agent for thread-safe writing to the trace file
2121
private Agent<PrintWriter> traceWriter
2222

23-
// Execution & CO2-footprint trace keys that are included into trace file
24-
private List<String> entryKeys = [
25-
'task_id', 'status', 'name', 'energy', 'CO2e', 'CO2eMarket', 'ci', '%cpu', 'memory', 'realtime', 'cpus',
26-
'powerdrawCPU', 'cpu_model', 'rawEnergyProcessor', 'rawEnergyMemory'
27-
]
28-
29-
// Mapping of entry keys to the CO2-footprint trace file header
30-
private final Map<String, String> keyHeaderMapping = [
31-
task_id: 'task_id', status: 'status',
32-
name:'name', energy: 'energy_consumption', CO2e: 'CO2e', CO2eMarket: 'CO2e_market', ci: 'carbon_intensity',
33-
'%cpu': '%cpu', memory: 'memory', realtime: 'realtime', cpus: 'cpus', powerdrawCPU: 'powerdraw_cpu',
34-
cpu_model: 'cpu_model', rawEnergyProcessor: 'raw_energy_processor', rawEnergyMemory: 'raw_energy_memory'
35-
]
36-
3723
/**
3824
* Constructor for the trace file.
3925
*
@@ -63,11 +49,8 @@ class TraceFileCreator extends BaseFileCreator {
6349
// Launch the agent for thread-safe writing
6450
traceWriter = new Agent<PrintWriter>(file)
6551

66-
// Write the header line to the trace file
67-
List<String> headers = entryKeys.collect { String entryName -> keyHeaderMapping.get(entryName) }
68-
6952
traceWriter.send {
70-
file.println( String.join('\t', headers) )
53+
file.println( String.join('\t', CO2Record.emissionMetrics) )
7154
file.flush()
7255
}
7356
}
@@ -81,7 +64,7 @@ class TraceFileCreator extends BaseFileCreator {
8164
void write(CO2Record co2Record){
8265
if (!created) { return }
8366

84-
List<String> recordedEntries = co2Record.getReadableEntries(entryKeys)
67+
List<String> recordedEntries = co2Record.getReadableEntries(CO2Record.emissionMetrics)
8568

8669
traceWriter.send { PrintWriter writer ->
8770
writer.println( String.join('\t', recordedEntries) )

src/main/nextflow/co2footprint/Records/CO2Record.groovy

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,29 @@ import nextflow.trace.TraceRecord
1616
@Slf4j
1717
@CompileStatic
1818
class CO2Record extends TraceRecord {
19-
static {
20-
FIELDS.putAll(
21-
[
22-
energy: 'mem',
23-
CO2e: 'num',
24-
CO2e_market: 'num',
25-
ci: 'num',
26-
'%cpu': 'perc',
27-
realtime: 'time',
28-
cpus: 'num',
29-
memory: 'mem',
30-
powerdrawCPU: 'num',
31-
cpu_model: 'str',
32-
rawEnergyProcessor: 'num',
33-
rawEnergyMemory: 'num',
34-
]
35-
)
36-
}
19+
static {
20+
FIELDS.putAll(
21+
[
22+
energy_consumption: 'mem',
23+
CO2e: 'num',
24+
CO2e_market: 'num',
25+
carbon_intensity: 'num',
26+
'%cpu': 'perc',
27+
realtime: 'time',
28+
cpus: 'num',
29+
memory: 'mem',
30+
powerdraw_cpu: 'num',
31+
cpu_model: 'str',
32+
raw_energy_processor: 'num',
33+
raw_energy_memory: 'num',
34+
]
35+
)
36+
}
3737

3838
// Stores keys that are related to the CO2 calculation
39-
final List<String> emissionMetrics = [
40-
'task_id', 'status', 'name', 'energy', 'CO2e', 'CO2e_market', 'ci', '%cpu', 'memory', 'realtime',
41-
'cpus', 'powerdrawCPU', 'cpu_model', 'rawEnergyProcessor', 'rawEnergyMemory'
39+
final static List<String> emissionMetrics = [
40+
'task_id', 'status', 'name', 'energy_consumption', 'CO2e', 'CO2e_market', 'carbon_intensity', '%cpu', 'memory', 'realtime',
41+
'cpus', 'powerdraw_cpu', 'cpu_model', 'raw_energy_processor', 'raw_energy_memory'
4242
]
4343

4444
// Stores non-CO₂ keys from the trace record and store them as traceKeys
@@ -90,18 +90,18 @@ class CO2Record extends TraceRecord {
9090

9191
// Define CO2-specific storage
9292
Map<String, Object> store = new LinkedHashMap<>([
93-
'energy': energy,
93+
'energy_consumption': energy,
9494
'CO2e': co2e,
9595
'CO2e_market': co2eMarket,
96-
'ci': ci,
96+
'carbon_intensity': ci,
9797
'%cpu': cpuUsage,
9898
'memory': memory,
9999
'realtime': Duration.of(time, 'h').scale('ms').value,
100100
'cpus': cpus,
101-
'powerdrawCPU': powerdrawCPU,
101+
'powerdraw_cpu': powerdrawCPU,
102102
'cpu_model': cpu_model,
103-
'rawEnergyProcessor': rawEnergyProcessor,
104-
'rawEnergyMemory': rawEnergyMemory,
103+
'raw_energy_processor': rawEnergyProcessor,
104+
'raw_energy_memory': rawEnergyMemory,
105105
])
106106

107107
// Add CO2-specific values to store + overwrite duplicate values
@@ -139,8 +139,8 @@ class CO2Record extends TraceRecord {
139139
Object thisValue = this.store[key]
140140

141141
// Weighted average by energy for carbon intensity and CPU power draw
142-
if (key in ['ci', 'powerdrawCPU']) {
143-
return Calculator.weightedAverage([thisValue, newValue], [store['energy'], record.store['energy']])
142+
if (key in ['carbon_intensity', 'powerdraw_cpu']) {
143+
return Calculator.weightedAverage([thisValue, newValue], [store['energy_consumption'], record.store['energy_consumption']])
144144
}
145145

146146
// Weighted average by time for CPU usage
@@ -195,16 +195,16 @@ class CO2Record extends TraceRecord {
195195
*/
196196
Map<String, ? extends Object> toRaw(String key, Object value=store[key]) {
197197
Map<String, ? extends Object> rawValue = switch (key) {
198-
case 'energy' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
198+
case 'energy_consumption' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
199199
case 'CO2e' -> Quantity.of(value, '', 'g').toMap()
200200
case 'CO2e_market' -> Quantity.of(value, '', 'g').toMap()
201201
case 'realtime' -> Duration.of(value, 'ms').scale('ms').toMap()
202-
case 'ci' -> Quantity.of(value, '', 'gCO₂e/kWh').toMap()
203-
case 'powerdrawCPU' -> Quantity.of(value, '', 'W').toMap()
202+
case 'carbon_intensity' -> Quantity.of(value, '', 'gCO₂e/kWh').toMap()
203+
case 'powerdraw_cpu' -> Quantity.of(value, '', 'W').toMap()
204204
case '%cpu' -> Percentage.of(value).toMap()
205205
case 'memory' -> Bytes.of(value, 'G').scale('').toMap()
206-
case 'rawEnergyProcessor' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
207-
case 'rawEnergyMemory' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
206+
case 'raw_energy_processor' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
207+
case 'raw_energy_memory' -> Quantity.of(value, 'k', 'Wh').scale('').toMap()
208208
default -> null
209209
}
210210
if (rawValue != null) { return rawValue }
@@ -233,16 +233,16 @@ class CO2Record extends TraceRecord {
233233
String toReadable(String key, Object value=store[key]) {
234234
if (value == null) { return NA }
235235
return switch (key) {
236-
case 'energy' -> new Quantity(value, 'k', 'Wh').toReadable()
236+
case 'energy_consumption' -> new Quantity(value, 'k', 'Wh').toReadable()
237237
case 'CO2e' -> new Quantity(value, '', 'g').toReadable()
238238
case 'CO2e_market' -> new Quantity(value, '', 'g').toReadable()
239239
case 'realtime' -> new Duration(value, 'ms').toReadable( 'ms', 'years')
240-
case 'ci' -> new Quantity(value, '', 'gCO₂e/kWh').toReadable()
241-
case 'powerdrawCPU' -> new Quantity(value, '', 'W').toReadable()
240+
case 'carbon_intensity' -> new Quantity(value, '', 'gCO₂e/kWh').toReadable()
241+
case 'powerdraw_cpu' -> new Quantity(value, '', 'W').toReadable()
242242
case '%cpu' -> new Percentage(value).toReadable()
243243
case 'memory' -> new Bytes(value, 'G', 'B').toReadable()
244-
case 'rawEnergyProcessor' -> new Quantity(value, 'k', 'Wh').toReadable()
245-
case 'rawEnergyMemory' -> new Quantity(value, 'k', 'Wh').toReadable()
244+
case 'raw_energy_processor' -> new Quantity(value, 'k', 'Wh').toReadable()
245+
case 'raw_energy_memory' -> new Quantity(value, 'k', 'Wh').toReadable()
246246
default -> getFmtStr(key)
247247
}
248248
}

src/main/nextflow/co2footprint/Records/CO2RecordTree.groovy

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ class CO2RecordTree {
8787
*/
8888
CO2RecordTree collectAdditionalMetrics(
8989
Map<String, Closure> metricTransformers = [
90-
CO2e_non_cached: { CO2Record record -> record.store.status != 'CACHED' ? record.CO2e : null },
91-
energy_non_cached: { CO2Record record -> record.store.status != 'CACHED' ? record.energy : null },
92-
CO2e_market: { CO2Record record -> record.CO2e_market },
93-
energy_market: { CO2Record record -> record.energy },
90+
CO2e_non_cached: { CO2Record record -> record.store.status != 'CACHED' ? record.store.CO2e : null },
91+
energy_consumption_non_cached: { CO2Record record -> record.store.status != 'CACHED' ? record.store.energy_consumption : null },
92+
CO2e_market: { CO2Record record -> record.store.CO2e_market },
93+
energy_consumption_market: { CO2Record record -> record.store.energy_consumption },
9494
]
9595
) {
9696
metricTransformers.each{ String name, Closure transformer ->
@@ -115,16 +115,16 @@ class CO2RecordTree {
115115
List<Object> values = []
116116

117117
// Catch special suffixes
118-
String suffix = '_' + key.split('_').drop(1).join('_')
118+
String caseSuffix = null
119+
if (key.endsWith('_non_cached')) { caseSuffix = '_non_cached' }
120+
119121
String croppedKey = key
120-
if (suffix == '_non_cached') {
121-
croppedKey = key.replace(suffix, '')
122-
}
122+
if (caseSuffix) { croppedKey = key.replace(caseSuffix, '') }
123123

124124
// Extract information
125125
if (!children && co2Record?.store?.containsKey(croppedKey)) {
126126
Object val = co2Record.store[croppedKey]
127-
if (suffix == '_non_cached' && (co2Record?.store?.status == 'CACHED')) {
127+
if (caseSuffix == '_non_cached' && (co2Record?.store?.status == 'CACHED')) {
128128
// do nothing
129129
}
130130
else {

src/resources/assets/CO2FootprintReportTemplate.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ <h3 id="metrics-total">Total emissions</h3>
148148
</div>
149149

150150
<div class="metric-card card p-1">
151-
<span class="metric">${co2_totals.energy}</span>
151+
<span class="metric">${co2_totals.energy_consumption}</span>
152152
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><mask id="ipSEnergySocket0-tab1"><g stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"><path d="M24 44c11.046 0 20-8.954 20-20S35.046 4 24 4S4 12.954 4 24s8.954 20 20 20Zm4-23v-5m-8 5v-5"/><path fill="#fff" d="M24 32a8 8 0 0 0 8-8v-3H16v3a8 8 0 0 0 8 8Z"/><path d="M24 44V32"/></g></mask><path fill="currentColor" d="M0 0h48v48H0z" mask="url(#ipSEnergySocket0-tab1)"/></svg>
153153
<span class="metric-title">Energy consumption</span>
154154
</div>
@@ -183,7 +183,7 @@ <h3 id="metrics-total">Total emissions</h3>
183183
</div>
184184

185185
<div class="metric-card card p-1">
186-
<span class="metric">${co2_totals.energy_non_cached}</span>
186+
<span class="metric">${co2_totals.energy_consumption_non_cached}</span>
187187
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><mask id="ipSEnergySocket0-tab2"><g stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"><path d="M24 44c11.046 0 20-8.954 20-20S35.046 4 24 4S4 12.954 4 24s8.954 20 20 20Zm4-23v-5m-8 5v-5"/><path fill="#fff" d="M24 32a8 8 0 0 0 8-8v-3H16v3a8 8 0 0 0 8 8Z"/><path d="M24 44V32"/></g></mask><path fill="currentColor" d="M0 0h48v48H0z" mask="url(#ipSEnergySocket0-tab2)"/></svg>
188188
<span class="metric-title">Energy consumption</span>
189189
</div>
@@ -219,7 +219,7 @@ <h3 id="metrics-total">Total emissions</h3>
219219
</div>
220220

221221
<div class="metric-card card p-1">
222-
<span class="metric" style="color:#808080">${co2_totals.energy_market}</span>
222+
<span class="metric" style="color:#808080">${co2_totals.energy_consumption_market}</span>
223223
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><mask id="ipSEnergySocket0-tab3"><g stroke="#D3D3D3" stroke-linecap="round" stroke-linejoin="round" stroke-width="4"><path d="M24 44c11.046 0 20-8.954 20-20S35.046 4 24 4S4 12.954 4 24s8.954 20 20 20Zm4-23v-5m-8 5v-5"/><path fill="#D3D3D3" d="M24 32a8 8 0 0 0 8-8v-3H16v3a8 8 0 0 0 8 8Z"/><path d="M24 44V32"/></g></mask><path fill="#D3D3D3" d="M0 0h48v48H0z" mask="url(#ipSEnergySocket0-tab3)"/></svg>
224224
<span class="metric-title" style="color:#808080">Energy consumption</span>
225225
</div>

src/resources/assets/CO2FootprintReportTemplate.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//
99
// Data contract (injected into window by the Groovy template renderer):
1010
// window.data.trace — array of per-task trace records
11-
// window.data.summary — per-process aggregated values (CO2e, energy, …)
11+
// window.data.summary — per-process aggregated values (CO2e, energy_consumption, …)
1212
// window.ciRecords — timestamped carbon-intensity readings
1313
// window.options — plugin configuration key/value pairs
1414

@@ -193,7 +193,7 @@ $(function () {
193193
*/
194194
function render() {
195195
const suffix = state.cached === 'all' ? '' : '_non_cached'
196-
const isEnergy = state.metric === 'energy'
196+
const isEnergy = state.metric === 'energy_consumption'
197197
const unit = isEnergy ? 'Wh' : 'g CO\u2082e'
198198
const axisTitle = isEnergy ? 'Energy consumption (Wh)' : 'CO\u2082e emissions (g)'
199199

@@ -333,7 +333,7 @@ $(function () {
333333

334334
// Wire up toggle buttons — each click updates state and re-renders.
335335
document.getElementById('pe-btn-co2e').addEventListener('click', () => { state.metric = 'CO2e'; setActive('pe-metric-btn', 'pe-btn-co2e'); render() })
336-
document.getElementById('pe-btn-energy').addEventListener('click', () => { state.metric = 'energy'; setActive('pe-metric-btn', 'pe-btn-energy'); render() })
336+
document.getElementById('pe-btn-energy').addEventListener('click', () => { state.metric = 'energy_consumption'; setActive('pe-metric-btn', 'pe-btn-energy'); render() })
337337
document.getElementById('pe-btn-all').addEventListener('click', () => { state.cached = 'all'; setActive('pe-cached-btn', 'pe-btn-all'); render() })
338338
document.getElementById('pe-btn-noncached').addEventListener('click', () => { state.cached = 'non_cached'; setActive('pe-cached-btn', 'pe-btn-noncached'); render() })
339339
document.getElementById('pe-btn-sort').addEventListener('click', () => {
@@ -383,17 +383,17 @@ $(function () {
383383
{ title: 'tag', data: 'tag' },
384384
{ title: 'status', data: 'status' },
385385
{ title: 'hash', data: 'hash' },
386-
{ title: energyConsumptionTitle, data: 'energy' },
387-
{ title: energyConsumptionProcessorTitle, data: 'rawEnergyProcessor' },
388-
{ title: energyConsumptionMemoryTitle, data: 'rawEnergyMemory' },
386+
{ title: energyConsumptionTitle, data: 'energy_consumption' },
387+
{ title: energyConsumptionProcessorTitle, data: 'raw_energy_processor' },
388+
{ title: energyConsumptionMemoryTitle, data: 'raw_energy_memory' },
389389
{ title: co2EmissionsTitle, data: 'CO2e' },
390390
{ title: `${co2EmissionsTitle} (market)`, data: 'CO2e_market' },
391-
{ title: 'carbon intensity', data: 'ci' },
391+
{ title: 'carbon intensity', data: 'carbon_intensity' },
392392
{ title: 'allocated cpus', data: 'cpus' },
393393
{ title: '%cpu', data: '%cpu' },
394394
{ title: 'allocated memory', data: 'memory' },
395395
{ title: 'realtime', data: 'time' },
396-
{ title: 'power draw (in W/core)', data: 'powerdrawCPU' },
396+
{ title: 'power draw (in W/core)', data: 'powerdraw_cpu' },
397397
{ title: 'cpu model', data: 'cpu_model' },
398398
],
399399
deferRender: true,
@@ -521,7 +521,7 @@ $(function () {
521521
let total = 0
522522
for (const task of window.data.trace) {
523523
if (task.start.time <= t0 && task.complete.time >= t1) {
524-
total += task.energy.raw.value
524+
total += task.energy_consumption.raw.value
525525
}
526526
}
527527

0 commit comments

Comments
 (0)