Skip to content

Commit 2d33e25

Browse files
authored
Merge pull request #2134 from sthaha/fix-active-energy-joules
refactor: energy data structs
2 parents a89474f + 356c2d7 commit 2d33e25

19 files changed

+655
-370
lines changed

internal/exporter/prometheus/collector/power_collector.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,21 +215,21 @@ func (c *PowerCollector) collectNodeMetrics(ch chan<- prometheus.Metric, node *m
215215
ch <- prometheus.MustNewConstMetric(
216216
c.nodeCPUJoulesDescriptor,
217217
prometheus.CounterValue,
218-
energy.Absolute.Joules(),
218+
energy.EnergyTotal.Joules(),
219219
zoneName, path,
220220
)
221221

222222
ch <- prometheus.MustNewConstMetric(
223223
c.nodeCPUActiveJoulesDesc,
224224
prometheus.CounterValue,
225-
energy.ActiveEnergy.Joules(),
225+
energy.ActiveEnergyTotal.Joules(),
226226
zoneName, path,
227227
)
228228

229229
ch <- prometheus.MustNewConstMetric(
230230
c.nodeCPUIdleJoulesDesc,
231231
prometheus.CounterValue,
232-
energy.IdleEnergy.Joules(),
232+
energy.IdleEnergyTotal.Joules(),
233233
zoneName, path,
234234
)
235235

@@ -280,7 +280,7 @@ func (c *PowerCollector) collectProcessMetrics(ch chan<- prometheus.Metric, proc
280280
ch <- prometheus.MustNewConstMetric(
281281
c.processCPUJoulesDescriptor,
282282
prometheus.CounterValue,
283-
usage.Absolute.Joules(),
283+
usage.EnergyTotal.Joules(),
284284
pidStr, proc.Comm, proc.Exe, string(proc.Type),
285285
proc.ContainerID, proc.VirtualMachineID,
286286
zoneName,
@@ -313,7 +313,7 @@ func (c *PowerCollector) collectContainerMetrics(ch chan<- prometheus.Metric, co
313313
ch <- prometheus.MustNewConstMetric(
314314
c.containerCPUJoulesDescriptor,
315315
prometheus.CounterValue,
316-
usage.Absolute.Joules(),
316+
usage.EnergyTotal.Joules(),
317317
id, container.Name, string(container.Runtime),
318318
zoneName,
319319
)
@@ -342,7 +342,7 @@ func (c *PowerCollector) collectVMMetrics(ch chan<- prometheus.Metric, vms monit
342342
ch <- prometheus.MustNewConstMetric(
343343
c.vmCPUJoulesDescriptor,
344344
prometheus.CounterValue,
345-
usage.Absolute.Joules(),
345+
usage.EnergyTotal.Joules(),
346346
id, vm.Name, string(vm.Hypervisor),
347347
zoneName,
348348
)

internal/exporter/prometheus/collector/power_collector_concurrency_test.go

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -123,31 +123,28 @@ func TestPowerCollectorWithRegistry(t *testing.T) {
123123
UsageRatio: 0.5,
124124
Zones: monitor.NodeZoneUsageMap{
125125
package0Zone: &monitor.NodeUsage{
126-
Absolute: nodePkgAbs,
127-
Delta: nodePkgDelta,
128-
ActiveEnergy: nodePkgDelta / 2,
129-
IdleEnergy: nodePkgDelta / 2,
130-
Power: nodePkgPower,
131-
ActivePower: nodePkgPower / 2,
132-
IdlePower: nodePkgPower / 2,
126+
EnergyTotal: nodePkgAbs,
127+
ActiveEnergyTotal: nodePkgDelta / 2,
128+
IdleEnergyTotal: nodePkgDelta / 2,
129+
Power: nodePkgPower,
130+
ActivePower: nodePkgPower / 2,
131+
IdlePower: nodePkgPower / 2,
133132
},
134133
dramZone: &monitor.NodeUsage{
135-
Absolute: nodeDramAbs,
136-
Delta: nodeDramDelta,
137-
ActiveEnergy: nodeDramDelta / 2,
138-
IdleEnergy: nodeDramDelta / 2,
139-
Power: nodeDramPower,
140-
ActivePower: nodeDramPower / 2,
141-
IdlePower: nodeDramPower / 2,
134+
EnergyTotal: nodeDramAbs,
135+
ActiveEnergyTotal: nodeDramDelta / 2,
136+
IdleEnergyTotal: nodeDramDelta / 2,
137+
Power: nodeDramPower,
138+
ActivePower: nodeDramPower / 2,
139+
IdlePower: nodeDramPower / 2,
142140
},
143141
package1Zone: &monitor.NodeUsage{
144-
Absolute: nodePkgAbs,
145-
Delta: nodePkgDelta,
146-
ActiveEnergy: nodePkgDelta / 2,
147-
IdleEnergy: nodePkgDelta / 2,
148-
Power: nodePkgPower,
149-
ActivePower: nodePkgPower / 2,
150-
IdlePower: nodePkgPower / 2,
142+
EnergyTotal: nodePkgAbs,
143+
ActiveEnergyTotal: nodePkgDelta / 2,
144+
IdleEnergyTotal: nodePkgDelta / 2,
145+
Power: nodePkgPower,
146+
ActivePower: nodePkgPower / 2,
147+
IdlePower: nodePkgPower / 2,
151148
},
152149
},
153150
}
@@ -252,13 +249,13 @@ func TestUpdateDuringCollection(t *testing.T) {
252249
UsageRatio: 0.5,
253250
Zones: monitor.NodeZoneUsageMap{
254251
packageZone: &monitor.NodeUsage{
255-
Absolute: 100 * device.Joule,
256-
Delta: 10 * device.Joule,
257-
ActiveEnergy: 5 * device.Joule,
258-
IdleEnergy: 5 * device.Joule,
259-
Power: 5 * device.Watt,
260-
ActivePower: 2.5 * device.Watt,
261-
IdlePower: 2.5 * device.Watt,
252+
EnergyTotal: 100 * device.Joule,
253+
ActiveEnergyTotal: 5 * device.Joule,
254+
IdleEnergyTotal: 5 * device.Joule,
255+
256+
Power: 5 * device.Watt,
257+
ActivePower: 2.5 * device.Watt,
258+
IdlePower: 2.5 * device.Watt,
262259
},
263260
},
264261
},

internal/exporter/prometheus/collector/power_collector_test.go

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,20 @@ func TestPowerCollector(t *testing.T) {
8989
UsageRatio: 0.5,
9090
Zones: monitor.NodeZoneUsageMap{
9191
packageZone: &monitor.NodeUsage{
92-
Absolute: nodePkgAbs,
93-
Delta: nodePkgDelta,
94-
ActiveEnergy: nodePkgDelta / 2, // 50% of delta is used
95-
IdleEnergy: nodePkgDelta / 2, // 50% of delta is idle
96-
Power: nodePkgPower,
97-
ActivePower: nodePkgPower / 2, // 50% of power is used
98-
IdlePower: nodePkgPower / 2, // 50% of power is idle
92+
EnergyTotal: nodePkgAbs,
93+
ActiveEnergyTotal: nodePkgDelta / 2, // 50% of delta is used
94+
IdleEnergyTotal: nodePkgDelta / 2, // 50% of delta is idle
95+
Power: nodePkgPower,
96+
ActivePower: nodePkgPower / 2, // 50% of power is used
97+
IdlePower: nodePkgPower / 2, // 50% of power is idle
9998
},
10099
dramZone: &monitor.NodeUsage{
101-
Absolute: nodeDramAbs,
102-
Delta: nodeDramDelta,
103-
ActiveEnergy: nodeDramDelta / 2, // 50% of delta is used
104-
IdleEnergy: nodeDramDelta / 2, // 50% of delta is idle
105-
Power: nodeDramPower,
106-
ActivePower: nodeDramPower / 2, // 50% of power is used
107-
IdlePower: nodeDramPower / 2, // 50% of power is idle
100+
EnergyTotal: nodeDramAbs,
101+
ActiveEnergyTotal: nodeDramDelta / 2, // 50% of delta is used
102+
IdleEnergyTotal: nodeDramDelta / 2, // 50% of delta is idle
103+
Power: nodeDramPower,
104+
ActivePower: nodeDramPower / 2, // 50% of power is used
105+
IdlePower: nodeDramPower / 2, // 50% of power is idle
108106
},
109107
},
110108
}
@@ -118,9 +116,8 @@ func TestPowerCollector(t *testing.T) {
118116
CPUTotalTime: 100,
119117
Zones: monitor.ZoneUsageMap{
120118
packageZone: {
121-
Absolute: 100 * device.Joule,
122-
Delta: 10 * device.Joule,
123-
Power: 5 * device.Watt,
119+
EnergyTotal: 100 * device.Joule,
120+
Power: 5 * device.Watt,
124121
},
125122
},
126123
},
@@ -133,9 +130,8 @@ func TestPowerCollector(t *testing.T) {
133130
Runtime: resource.PodmanRuntime,
134131
Zones: monitor.ZoneUsageMap{
135132
packageZone: {
136-
Absolute: 100 * device.Joule,
137-
Delta: 10 * device.Joule,
138-
Power: 5 * device.Watt,
133+
EnergyTotal: 100 * device.Joule,
134+
Power: 5 * device.Watt,
139135
},
140136
},
141137
},
@@ -148,9 +144,8 @@ func TestPowerCollector(t *testing.T) {
148144
Hypervisor: resource.KVMHypervisor,
149145
Zones: monitor.ZoneUsageMap{
150146
packageZone: {
151-
Absolute: 100 * device.Joule,
152-
Delta: 10 * device.Joule,
153-
Power: 5 * device.Watt,
147+
EnergyTotal: 100 * device.Joule,
148+
Power: 5 * device.Watt,
154149
},
155150
},
156151
},

internal/exporter/stdout/stdout.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,8 @@ func writeNode(out io.Writer, node *monitor.Node) {
124124
for zone, usage := range node.Zones {
125125
rows = append(rows, []string{
126126
zone.Name(),
127-
usage.Delta.String(),
128127
usage.Power.String(),
129-
usage.Absolute.String(),
128+
usage.EnergyTotal.String(),
130129
})
131130
}
132131
sort.Slice(rows, func(i, j int) bool {
@@ -136,7 +135,7 @@ func writeNode(out io.Writer, node *monitor.Node) {
136135
table.Configure(func(cfg *tablewriter.Config) {
137136
cfg.Row.Formatting.Alignment = tw.AlignRight
138137
})
139-
table.Header([]string{"Zone", "Delta(W)", "Power(W)", "Absolute(J)"})
138+
table.Header([]string{"Zone", "Power(W)", "Absolute(J)"})
140139
_ = table.Bulk(rows)
141140
// removed because testcase gets a trailing whitespace which fails CI
142141
// table.Caption(tw.Caption{

internal/exporter/stdout/stdout_test.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ func Test_print(t *testing.T) {
133133
assert.NoError(t, err, "unexpected time parse error")
134134
write(&buf, now, getTestNodeSnapshot())
135135
expected := `
136-
┌─────────┬─────────────┬─────────────┬────────────────┐
137-
│ ZONE │ DELTA ( W ) │ POWER ( W ) │ ABSOLUTE ( J ) │
138-
├─────────┼─────────────┼─────────────┼────────────────┤
139-
│ dram │ 234.00J │ 2.00W │ 2340.00J │
140-
│ package │ 123.00J │ 12.00W │ 12300.00J │
141-
└─────────┴─────────────┴─────────────┴────────────────┘
136+
┌─────────┬─────────────┬────────────────┐
137+
│ ZONE │ POWER ( W ) │ ABSOLUTE ( J ) │
138+
├─────────┼─────────────┼────────────────┤
139+
│ dram │ 2.00W │ 2340.00J │
140+
│ package │ 12.00W │ 12300.00J │
141+
└─────────┴─────────────┴────────────────┘
142142
`
143143
expected = strings.TrimLeft(expected, "\n")
144144
assert.Equal(t, expected, buf.String())
@@ -156,25 +156,21 @@ func getTestNodeData() *monitor.Node {
156156
dramZone := device.NewMockRaplZone("dram", 0, "/sys/class/powercap/intel-rapl/intel-rapl:0:1", 1000)
157157

158158
nodePkgAbs := 12300 * device.Joule
159-
nodePkgDelta := 123 * device.Joule
160159
nodePkgPower := 12 * device.Watt
161160

162161
nodeDramAbs := 2340 * device.Joule
163-
nodeDramDelta := 234 * device.Joule
164162
nodeDramPower := 2 * device.Watt
165163

166164
// Create test node Snapshot
167165
return &monitor.Node{
168166
Zones: monitor.NodeZoneUsageMap{
169167
packageZone: &monitor.NodeUsage{
170-
Absolute: nodePkgAbs,
171-
Delta: nodePkgDelta,
172-
Power: nodePkgPower,
168+
EnergyTotal: nodePkgAbs,
169+
Power: nodePkgPower,
173170
},
174171
dramZone: &monitor.NodeUsage{
175-
Absolute: nodeDramAbs,
176-
Delta: nodeDramDelta,
177-
Power: nodeDramPower,
172+
EnergyTotal: nodeDramAbs,
173+
Power: nodeDramPower,
178174
},
179175
},
180176
}

internal/monitor/container.go

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ func (pm *PowerMonitor) firstContainerRead(snapshot *Snapshot) error {
2929
// Initialize each zone with zero values
3030
for _, zone := range zones {
3131
container.Zones[zone] = &Usage{
32-
Absolute: Energy(0),
33-
Delta: Energy(0),
34-
Power: Power(0),
32+
EnergyTotal: Energy(0),
33+
Power: Power(0),
3534
}
3635
}
3736

@@ -59,7 +58,7 @@ func (pm *PowerMonitor) calculateContainerPower(prev, newSnapshot *Snapshot) err
5958
}
6059

6160
node := pm.resources.Node()
62-
nodeCPUTimeDelta := node.CPUTimeDelta
61+
nodeCPUTimeDelta := node.ProcessTotalCPUTimeDelta
6362

6463
pm.logger.Debug("Calculating container power",
6564
"node.cpu.time", nodeCPUTimeDelta,
@@ -85,33 +84,32 @@ func (pm *PowerMonitor) calculateContainerPower(prev, newSnapshot *Snapshot) err
8584
// For each zone in the node, calculate container's share
8685
for zone, nodeZoneUsage := range newSnapshot.Node.Zones {
8786
// Skip zones with zero power to avoid division by zero
88-
if nodeZoneUsage.Power == 0 || nodeZoneUsage.Delta == 0 || nodeCPUTimeDelta == 0 {
87+
if nodeZoneUsage.ActivePower == 0 || nodeZoneUsage.activeEnergy == 0 || nodeCPUTimeDelta == 0 {
8988
container.Zones[zone] = &Usage{
90-
Power: Power(0),
91-
Delta: Energy(0),
92-
Absolute: Energy(0),
89+
Power: Power(0),
90+
EnergyTotal: Energy(0),
9391
}
9492
continue
9593
}
9694

9795
cpuTimeRatio := c.CPUTimeDelta / nodeCPUTimeDelta
98-
// Calculate container's share of this zone's power and energy
99-
container.Zones[zone] = &Usage{
100-
Power: Power(cpuTimeRatio * nodeZoneUsage.ActivePower.MicroWatts()),
101-
Delta: Energy(cpuTimeRatio * float64(nodeZoneUsage.ActiveEnergy)),
102-
}
10396

104-
// If we have previous data for this container and zone, add to absolute energy
97+
// Calculate energy delta for this interval
98+
activeEnergy := Energy(cpuTimeRatio * float64(nodeZoneUsage.activeEnergy))
99+
100+
// Calculate absolute energy based on previous data
101+
// New container, starts with delta
102+
absoluteEnergy := activeEnergy
105103
if prev, exists := prev.Containers[id]; exists {
106104
if prevUsage, hasZone := prev.Zones[zone]; hasZone {
107-
container.Zones[zone].Absolute = prevUsage.Absolute + container.Zones[zone].Delta
108-
} else {
109-
// TODO: unlikely; so add telemetry for this
110-
container.Zones[zone].Absolute = container.Zones[zone].Delta
105+
absoluteEnergy += prevUsage.EnergyTotal
111106
}
112-
} else {
113-
// New container, starts with delta
114-
container.Zones[zone].Absolute = container.Zones[zone].Delta
107+
}
108+
109+
// Calculate container's share of this zone's power and energy
110+
container.Zones[zone] = &Usage{
111+
Power: Power(cpuTimeRatio * nodeZoneUsage.ActivePower.MicroWatts()),
112+
EnergyTotal: absoluteEnergy,
115113
}
116114
}
117115

0 commit comments

Comments
 (0)