Skip to content

Linux RAPL may double-count CPU power on multi-die AMD, while Windows EMI explicitly guards against it #1379

Description

@davidberenstein1957

The Windows EMI backend detects package channels that mirror the same underlying energy counter and drops the duplicates. The Linux powercap path does not, and sums them. If the premise behind the Windows guard is correct, CodeCarbon overstates CPU power on multi-die AMD parts (Threadripper, EPYC) on Linux by a factor equal to the die count.

I want to be upfront that the last step here needs hardware to settle — but the codebase currently asserts both positions, so one of them is wrong.

The two paths

Windows deliberately discards mirrored per-die channels. From codecarbon/core/windows_emi.py:310-324:

Multi-die CPUs (e.g. AMD Ryzen Threadripper / EPYC) expose one package channel per die, but every die mirrors the same socket-wide RAPL counter. Summing those channels multiplies the reported CPU power by the number of dies, exactly like the package-0-die-0 / package-0-die-1 duplicates seen through the Linux powercap interface.

That docstring names the Linux case directly and calls it the same defect. The guard was added deliberately and recently (17c78568 "Multi-die fix for Windows EMI", 15a73945 "Fix multiple-counting").

Linux sums them. _classify_domains (codecarbon/core/cpu.py:648-649) puts any domain whose name contains package into package_domains:

if "package" in domain_lower:
    package_domains.append(domain_tuple)

_deduplicate_domains (cpu.py:746-761) then keys the map on domain_name. Since package-0-die-0 and package-0-die-1 are distinct names, both survive deduplication and both are summed. There is no mirrored-counter check anywhere on the Linux path.

Supporting evidence

docs/explanation/rapl.md contains a worked Threadripper example whose summary table reads:

package-0-die-0: 68 W | package-0-die-1: 68 W | CodeCarbon: 137 W

Two dies reporting an identical 68 W, summed to 137 W. Under the Windows docstring premise that is the double-count, observed on real hardware — the documentation has been presenting the symptom as correct behaviour.

Impact if confirmed

CPU power roughly doubled on 2-die parts and worse on higher die counts, for the exact hardware class most likely to be running large training jobs on Linux. It would be silent: no warning, and a plausible-looking number. It would also affect every downstream figure, since CPU energy feeds total energy and emissions.

What needs settling

Whether package-0-die-0 and package-0-die-1 in Linux powercap report independent per-die counters or mirrors of one socket-wide counter. This is a hardware question and may vary by CPU generation and kernel version. Reading identical values on a loaded machine is strong evidence of mirroring, which is the heuristic the Windows path already uses (_counters_match, windows_emi.py:305-307).

If they mirror, the fix is to port the Windows mirrored-channel detection to the Linux domain selection rather than reimplementing it. If they are genuinely independent, then the Windows guard is over-aggressive and is under-reporting on Windows, and the docstring claim about Linux should be corrected.

Either way the two backends should not disagree about the same hardware.

Note

Documentation PRs currently in flight touch rapl.md, including the Threadripper walkthrough. Whichever way this is resolved, that page should stop presenting 68 + 68 → 137 W as confirmed-correct behaviour until it is.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions