Skip to content

Add support for Windows Energy Meter Interface (EMI)#1263

Open
benoit-cty wants to merge 3 commits into
masterfrom
windows_support
Open

Add support for Windows Energy Meter Interface (EMI)#1263
benoit-cty wants to merge 3 commits into
masterfrom
windows_support

Conversation

@benoit-cty

Copy link
Copy Markdown
Contributor

Description

Adds a new CPU power-measurement backend for Windows: the built-in Windows Energy Meter Interface (EMI), available since Windows 11. EMI exposes the same RAPL energy counters CodeCarbon already reads on Linux (/sys/class/powercap), but through a standard OS device interface — no third-party driver, no administrator rights, and no extra Python dependency.

Changes:

  • New codecarbon/core/windows_emi.py: a stdlib-only ctypes implementation (WindowsEMI class + is_emi_available() probe) that enumerates GUID_DEVICE_ENERGY_METER devices, reads their metadata/channels, and computes energy/power deltas from the cumulative picowatt-hour counters. Mirrors the existing IntelRAPL semantics: package channels are preferred over PP0/PP1 subdomains to avoid double-counting, with an opt-in rapl_include_dram flag.
  • codecarbon/external/hardware.py: new "windows_emi" CPU mode, treated as an energy-delta backend alongside "intel_rapl".
  • codecarbon/core/resource_tracker.py: on Windows, CodeCarbon now tries EMI first, then falls back to Intel Power Gadget (kept for backward compatibility on machines where it's already installed), then to CPU-load estimation.
  • codecarbon/core/hardware_cache.py: clears the EMI availability cache alongside the other hardware caches.
  • docs/explanation/methodology.md: documents the new Windows measurement path and its limitations.
  • New tests in tests/test_windows_emi.py (parsing, channel selection, energy/power computation, error handling, availability probe), plus updates to tests/test_resource_tracker.py, tests/test_cpu_load.py, and tests/test_tracking_inference.py to reflect the new backend priority.

Related Issue

Resolves #457

Motivation and Context

Intel Power Gadget — CodeCarbon's only real (non-estimated) CPU power source on Windows — was discontinued by Intel in December 2023 and can no longer be downloaded, so in practice every Windows user has been silently falling back to TDP × CPU-load estimation for over two years.

The issue originally proposed Intel PCM as a replacement, but it's Intel-only and notoriously hard to install (kernel driver, admin rights, no pip package) — unlikely to ever be installed by an actual CodeCarbon user. A follow-up comment proposed LibreHardwareMonitor / PyHardwareMonitor, which does work for both Intel and AMD, but still requires administrator privileges and ships the WinRing0 kernel driver (which has known CVEs and is increasingly blocked by AV/EDR and Microsoft's vulnerable-driver blocklist), plus a pythonnet + .NET Framework dependency.

Windows 11 already exposes the same RAPL counters natively through the Energy Meter Interface — the same mechanism Firefox's power profiler switched to after Power Gadget's deprecation (Mozilla bug 1774844). It works for Intel and AMD, requires no admin rights, no kernel driver, and no extra dependency (validated: reads succeed from an unelevated process). This lets CodeCarbon get real hardware measurements on Windows again with zero added friction for users.

Limitations, documented in the methodology page: EMI requires Windows 11 on bare metal (Windows 10 only reports on devices with dedicated metering hardware, e.g. Surface Book); it won't work inside VMs, same as RAPL on Linux. Where it isn't available, CodeCarbon transparently falls back to Power Gadget (if installed) and then CPU-load estimation, so there's no regression for any existing setup.

How Has This Been Tested?

  • Added tests/test_windows_emi.py: unit tests for EMI metadata/channel parsing (V1 and V2), measurement parsing, package-channel selection logic (including multi-package and DRAM-inclusion cases), WindowsEMI setup/energy computation (including negative-counter-delta and zero-time-delta edge cases), and is_emi_available() caching behavior — all via mocks, no real hardware access required.
  • Updated tests/test_resource_tracker.py, tests/test_cpu_load.py, and tests/test_tracking_inference.py for the new Windows backend priority (EMI before Power Gadget) and to account for a coarser counter-refresh granularity (<= instead of < for one assertion).
  • Manually validated against real hardware on a Windows 11 bare-metal machine (Intel Core Ultra 7 265H): a standalone probe script confirmed EMI device discovery and readable RAPL_Package0_PKG/DRAM/PP0/PP1 channels while running unelevated (~4 W idle). Then ran a full EmissionsTracker session under synthetic CPU load and confirmed CPU Tracking Method: Windows EMI was selected automatically, with power readings around 15 W and correctly computed emissions.
  • Ran the full existing test suite (pytest tests, excluding modules gated on unrelated optional dependencies not installed in this environment — dash, joserfc) to confirm no regressions: all passing.
  • Verified lint/formatting with black, isort, and flake8 per the project's pre-commit config.

Screenshots (if appropriate):

N/A (backend/library change, no UI impact).

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

AI Usage Disclosure

Please refer to docs/how-to/ai-policy.md for detailed guidelines on how to disclose AI usage in your PR. Accurately completing this section is mandatory.

  • 🟥 AI-vibecoded: You cannot explain the logic. Car analogy : the car drive by itself, you are outside it and just tell it where to go.
  • 🟠 AI-generated: Car analogy : the car drive by itself, you are inside and give instructions.
  • ⭐ AI-assisted. Car analogy : you drive the car, AI help you find your way.
  • ♻️ No AI used. Car analogy : you drive the car.

Checklist:

Go over all the following points, and put an x in all the boxes that apply.

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the docs/how-to/contributing.md document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@benoit-cty benoit-cty requested a review from a team as a code owner July 5, 2026 17:34
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.42857% with 68 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.82%. Comparing base (3161c53) to head (afdda04).

Files with missing lines Patch % Lines
codecarbon/core/windows_emi.py 69.44% 66 Missing ⚠️
codecarbon/external/hardware.py 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1263      +/-   ##
==========================================
- Coverage   89.64%   88.82%   -0.83%     
==========================================
  Files          48       49       +1     
  Lines        4771     5001     +230     
==========================================
+ Hits         4277     4442     +165     
- Misses        494      559      +65     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intel® Power Gadget is being deprecated

1 participant