Repository navigation
Conversation
|
|
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (21.64%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #2566 +/- ##
==========================================
- Coverage 92.41% 86.71% -5.71%
==========================================
Files 58 61 +3
Lines 6121 6464 +343
==========================================
- Hits 5657 5605 -52
- Misses 329 724 +395
Partials 135 135 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
📊 Profiling reports are ready to be viewed
💻 CPU Comparison with base Kepler💾 Memory Comparison with base Kepler (Inuse)💾 Memory Comparison with base Kepler (Alloc)⬇️ Download the Profiling artifacts from the Actions Summary page 📦 Artifact name: 🔧 Or use GitHub CLI to download artifacts: gh run download 36509427626 -n profile-artifacts-2566 |
Consolidate all CPU-specific power measurement implementations (hwmon, RAPL, fake, mock) into cpu package. This refactor decouples CPU power metering logic from the generic device layer, improving code organization, modularity and maintainability while preserving existing functionality. Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
Add support for AMD Energy System Management Interface (E-SMI) for CPU power monitoring on AMD platforms. This enables accurate power measurements on AMD EPYC processors through E-SMI C library and sysfs fallback, including per-socket DIMM power consumption monitoring. Key changes: - Add ESMI CPU power meter implementation (internal/device/cpu/esmi/) - Support goamdsmi backend via E-SMI C library (libe_smi64.so) - Support per-socket DIMM power consumption monitoring (dimm backend) - Include sysfs fallback backend (pure Go, no dependencies) - Add experimental.esmi.enabled config flag - Integrate ESMI into CPU meter selection via cpu.preferredMeters - Shared E-SMI library initialization to prevent re-init crashes - Individual zone naming (package-N, core-N, dimm-N) matching sysfs behavior The ESMI meter is automatically prepended to cpu.preferredMeters when experimental.esmi.enabled is set to true, making it the first-tried CPU power source on supported AMD hardware. Zone types: - package-N: Per-socket energy (µJ) + instantaneous power (W) - core-N: Per-logical-thread energy (µJ) - dimm-N: Per-socket aggregated DIMM instantaneous power (W) Build options: - Default build: Uses sysfs backend only (no external dependencies) - With -tags goamdsmi: Adds E-SMI C library backends (requires libe_smi64.so) Installation: /opt/e-sms/e_smi/ or adjust CGO paths in source files Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
- Update configuration documentation for experimental.esmi.enabled - Add config examples in compose/dev, compose/default, k8s, and helm - Add comprehensive unit tests for ESMI power meter (16.9% coverage) - Tests cover PowerMeter interface, Init, Zones, and caching behavior Signed-off-by: Sivaprasad Tummala <sivaprasad.tummala@amd.com>
4f46308 to
2b8be94
Compare
|
📊 Profiling reports are ready to be viewed
💻 CPU Comparison with base Kepler💾 Memory Comparison with base Kepler (Inuse)💾 Memory Comparison with base Kepler (Alloc)⬇️ Download the Profiling artifacts from the Actions Summary page 📦 Artifact name: 🔧 Or use GitHub CLI to download artifacts: gh run download 37283531943 -n profile-artifacts-2566 |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Power units, sysfs zone normalization, primary-zone selection, and removed factory coverage must be corrected.
Review effort: Balanced
Findings: 2
Open (4)
What changed in this PR
Adds AMD E-SMI CPU power monitoring while reorganizing CPU meter implementations into a dedicated package.
Changes:
- Adds sysfs and optional CGo E-SMI backends, including DIMM monitoring.
- Adds ESMI configuration, manifests, and documentation.
- Refactors CPU meter interfaces, implementations, and tests.
| File | Description |
|---|---|
manifests/k8s/configmap.yaml |
Adds ESMI configuration. |
manifests/helm/kepler/values.yaml |
Adds Helm ESMI setting. |
Makefile |
Adds tagged CGo builds. |
internal/monitor/node_test.go |
Updates CPU test imports. |
internal/monitor/monitor.go |
Uses CPU package interface. |
internal/monitor/monitor_test.go |
Updates CPU test helpers. |
internal/monitor/monitor_concurrency_test.go |
Updates fake meter imports. |
internal/monitor/mock_utils.go |
Adapts mocks to device zones. |
internal/exporter/stdout/stdout_test.go |
Updates zone mock imports. |
internal/exporter/prometheus/collector/power_collector_test.go |
Updates collector test zones. |
internal/exporter/prometheus/collector/power_collector_concurrency_test.go |
Updates concurrency fixtures. |
internal/device/power_meter.go |
Moves shared zone interface. |
internal/device/energy_zone.go |
Exports zone key and count. |
internal/device/energy_zone_test.go |
Updates exported key tests. |
internal/device/cpu/rapl_zone_filtering_test.go |
Moves RAPL tests to CPU package. |
internal/device/cpu/rapl_sysfs_power_meter.go |
Moves RAPL implementation. |
internal/device/cpu/rapl_sysfs_power_meter_test.go |
Updates moved RAPL tests. |
internal/device/cpu/mock_cpu_power_meter.go |
Moves CPU meter mocks. |
internal/device/cpu/hwmon_power_meter.go |
Moves hwmon implementation. |
internal/device/cpu/hwmon_power_meter_test.go |
Updates moved hwmon tests. |
internal/device/cpu/hwmon_chip_rules.go |
Moves hwmon rules. |
internal/device/cpu/fake_cpu_power_meter.go |
Moves fake CPU meter. |
internal/device/cpu/fake_cpu_power_meter_test.go |
Updates fake meter tests. |
internal/device/cpu/esmi/sysfs_reader.go |
Adds AMD sysfs reader. |
internal/device/cpu/esmi/power_meter.go |
Adds ESMI meter selection. |
internal/device/cpu/esmi/power_meter_test.go |
Tests common ESMI behavior. |
internal/device/cpu/esmi/goamdsmi_reader.go |
Adds CGo E-SMI reader. |
internal/device/cpu/esmi/esmi_init.go |
Shares E-SMI initialization. |
internal/device/cpu/esmi/dimm_reader.go |
Adds DIMM power monitoring. |
internal/device/cpu/esmi/backends_goamdsmi.go |
Registers tagged backends. |
internal/device/cpu/esmi/backends_default.go |
Registers default sysfs backend. |
internal/device/cpu/create_meter.go |
Adds ESMI factory dispatch. |
internal/device/cpu/cpu_power_meter.go |
Defines CPU meter interface. |
internal/device/cpu_power_meter_test.go |
Removes previous factory tests. |
hack/config.yaml |
Documents ESMI configuration. |
docs/user/configuration.md |
Documents ESMI usage. |
config/config.go |
Adds ESMI flags and validation. |
config/config_cpu_test.go |
Tests ESMI preference injection. |
compose/dev/kepler-dev/etc/kepler/config.yaml |
Adds development ESMI setting. |
compose/default/kepler/etc/kepler/config.yaml |
Adds default ESMI setting. |
cmd/kepler/main.go |
Uses refactored CPU factory. |
.gitignore |
Adds generated-file exclusions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| return 0, fmt.Errorf("esmi/dimm: all DIMM reads failed for socket %d", z.socketIdx) | ||
| } | ||
|
|
||
| return device.Power(float64(totalPowerMw) / 1000.0), nil |
| if C.esmi_socket_power_read(C.uint32_t(z.socketIdx), &power) != 0 { | ||
| return 0, fmt.Errorf("esmi: esmi_socket_power_get failed for socket %d", z.socketIdx) | ||
| } | ||
| return device.Power(float64(power) / 1000.0), nil |
| // Normalize AMD zone names to match RAPL conventions | ||
| if baseName == "socket" { | ||
| return "package" | ||
| } |
| "load the amd_energy kernel module or install libamd_smi.so " + | ||
| "and rebuild with -tags goamdsmi", |
bitflicker64
left a comment
There was a problem hiding this comment.
Thanks for picking up AMD support. DIMM power on AMD is something Kepler can't report today, and that part is worth having. Most of the rest of the diff either repeats what Kepler already does or exists only to support other parts of this PR. Here is what I'd cut, biggest first.
-
Keep the meter in
internal/device. Theinternal/device/cpumove is about 1,150 lines of churn across 25 files. ESMI doesn't need it. The only constraint is thatesmi, as a subpackage, importsdevice, so the factory indevicecan't import it back. If the ESMI files sit next torapl_sysfs_power_meter.goandhwmon_power_meter.go, that goes away and the whole refactor commit can be dropped. The test mocks inesmi/power_meter_test.gocould then reuse the existing ones inmock_cpu_power_meter.go. -
Drop
sysfs_reader.goandbackends_goamdsmi.go, and cutbackends_default.godown to a stub that returns an error without the tag. The hwmon meter'sdiscoverZones()already readsenergy*_inputandpower*_inputfrom any hwmon chip, which covers bothamd_energyandamd_hsmp_hwmon.amd_energywas also removed from mainline in 5.13. Users without the tag can setcpu.preferredMeters: ["hwmon"]. This saves about 320 lines. -
Replace the backend selection framework with a direct call. With only the E-SMI library left,
backendCandidate, theadditiveflag,mergedReader, theReaderinterface and the primary/additive probe loop inNewCPUPowerMeterare not needed. The constructor can callesmiInit()and build the zones.Init()already probes them again anyway. This saves about 110 lines. -
Drop
experimental.esmi.enabled. It does the same thing ascpu.preferredMeters: ["esmi", "rapl", "hwmon"], and this PR already acceptsesmiinValidate(). Removing it also removes the block inApplyCpuMeterDeprecations, the CLI flag, theIsFeatureEnabledcase, the docs section, and the edits to the compose, hack, Helm and k8s configs. This saves about 110 lines. -
Shrink
PrimaryEnergyZone()and dropfilterZones(). Nothing in production calls the esmiWithZoneFilter, becausecreate_meter.goonly passesWithLogger. If the socket and DIMM zones are namedpackageanddimmwith the socket as the index, the way RAPL names them,groupZonesByName()aggregates them like RAPL does andPrimaryEnergyZone()becomes a lookup ofpackage. This saves about 80 lines. -
Drop the core zones in
goamdsmi_reader.go. There is onecore-Nzone per logical CPU, and each zone is azonelabel value on process, container, pod and VM metrics, so a 256-core host gets 256 or more series per workload per metric. Attribution splits every zone by node-wide CPU time anyway, so the per-thread counters don't make it more precise. Keep the package zones.CreateCPUMeteruses a single CPU meter, so anesmimeter with only DIMM zones would replace RAPL instead of adding to it. This saves about 65 lines. -
Use one cgo preamble.
esmi_init.go,dimm_reader.goandgoamdsmi_reader.goeach repeat the/opt/e-smsflags, andesmi_num_socketsis defined twice. The energy and power wrappers only cast the return value, so Go can callC.esmi_socket_energy_getdirectly and compare againstC.ESMI_SUCCESS. Only the DIMM helper needs to stay, because cgo can't read the bitfields instruct dimm_power. This saves about 50 lines. -
Drop the Makefile block.
make build BUILD_ARGS="-tags goamdsmi"already works on main,CC ?= ccmatches make's built-in default, and nothing here is C++, so-lstdc++and-std=c++11aren't needed. This saves about 20 lines. -
Delete
dimmBackend()andzoneNames(). Nothing calls them. This saves about 15 lines.
All together, that's about 770 of the 1,460 lines the two feature commits add, plus the 1,150-line package move. What's left is a socket and DIMM meter of a few hundred lines that's easy to review.
Separately from the cuts, three things need fixing either way. Socket and DIMM power are divided by 1000, but device.Power is in microwatts, so both come out a million times too small, as Copilot already flagged. PrimaryEnergyZone() looks up package while the zones are named package-N, so it falls through to whichever energy zone comes first out of a map, usually a core zone. The test presets topZone, so it doesn't catch this. And the move deletes the 12 TestCreateCPUMeter_* and TestBuildCPUMeter_* tests instead of moving them.



Summary
This PR adds support for AMD Energy System Management Interface (E-SMI) for CPU power monitoring on AMD EPYC platforms. It includes two commits:
Key Features
goamdsmi: Uses E-SMI C library (libe_smi64.so) for socket/core energy + DIMM powersysfs: Pure Go fallback using amd_energy kernel moduleexperimental.esmi.enabledZone Types
Build Options
make build- Uses sysfs backend only (no external deps)make build TAGS=goamdsmi- Enables all backends (requires libe_smi64.so)Test Results
✅ All tests passing (18/18 packages, 84-100% coverage)
✅ Verified on AMD EPYC system with 2 sockets, 256 cores, 16 DIMMs
Sample Metrics
Configuration Example
Related Issues
Adds AMD platform support for CPU power monitoring to complement existing Intel RAPL support.
Checklist
🤖 Generated with Claude Code