feat: add codecarbon doctor command - #1360
Open
davidberenstein1957 wants to merge 3 commits into
Open
Conversation
Report per component whether power is measured from a hardware energy counter or estimated from a model, why a better method was not used, and the concrete fix. --json for CI and bug reports, --strict to fail a job when a machine silently falls back to estimation. Closes #1350 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1360 +/- ##
==========================================
+ Coverage 91.39% 91.66% +0.26%
==========================================
Files 49 50 +1
Lines 5056 5195 +139
==========================================
+ Hits 4621 4762 +141
+ Misses 435 433 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- --strict ignored nothing, and RAM is ESTIMATED on every machine, so it exited 1 everywhere. Exempt RAM (no platform exposes a DRAM counter), the same rationale as an absent GPU being UNAVAILABLE, via diagnostics.strict_failures(). - dispatch on isinstance instead of type(hw).__name__, so a rename of the hardware classes fails at import instead of silently dropping components. - pass allow_multiple_runs=True: with a live run, __init__ returns early and _ensure_hardware_ready() blows up on unset attributes. - quiet the tracker's start-up logs around the report, restoring the caller's log level afterwards. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidberenstein1957
marked this pull request as ready for review
August 12, 2026 19:14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
codecarbon doctor, a command that tells the user, per power component, whether CodeCarbon measures it or estimates it, why a better method was not used, and the concrete fix.Today the fallbacks are invisible: on a Linux box where
/sys/class/powercap/intel-raplis root-only the CPU silently drops to a load-over-TDP model, an unrecognised CPU model silently uses a generic TDP constant, RAM is always modelled — andcodecarbon detectprints a correct hardware list that suggests all is well. This is a disclosure problem, not a measurement problem.No new dependency, no new measurement code: it reads the mode each hardware object landed in (
CPU._mode,CPU._is_generic_tdp) and reuses the existing availability checks (powermetrics.is_powermetrics_available,windows_emi.is_emi_available) to explain the failure.User-facing surface
MEASURED/ESTIMATED/UNAVAILABLE, the method, aWhy:line and aFix:line, plus a one-line summary;--json: the same report as JSON, for CI checks and bug reports;--strict: exit 1 when any component isESTIMATED(an absent GPU isUNAVAILABLEand does not fail, since "this machine should have had a GPU" is guesswork);codecarbon detectgains a closing pointer todoctor.Public API:
codecarbon.diagnostics.ComponentDiagnosticanddiagnose(hardware) -> list[ComponentDiagnostic].Sample:
The reason distinguishes "no RAPL interface on this platform" from "RAPL is there but unreadable" — that distinction is the point of the command; without it the user is back on the RAPL how-to page guessing which stanza applies.
How it was verified
tests/test_diagnostics.py: 10 tests covering measured/estimated CPU classification, the RAPL absent-vs-unreadable distinction against a fake powercap tree intmp_path, generic-TDP flagging, RAM always estimated, GPU present/absent, the JSON schema, and--strictexit codes viaCliRunner.uv run pytest tests/test_diagnostics.py tests/cli tests/test_package_integrity.py -q→ 82 passed.sudo; both text and--jsonoutput are correct.blackandruff checkrun scoped to the touched files (the repo-widetask format/task lintreformat ~120 unrelated files, so they were not run); remaining ruff findings in these files are the same pre-existing style class as the rest ofcli/main.py.Deliberately left out
These change behaviour for every existing user and belong in their own PR with their own release note:
EmissionsTracker.__init__when a component is estimated;measurement_qualityprovenance field onEmissionsData/ the CSV — the vocabulary is settled here (measured/estimated/unavailable) so a follow-up can adopt it;why_unavailable()methods onrapl.py,powermetrics.py,windows_emi.py,gpu_*.py; the reason is derived from the existing availability checks instead, which covers the common Linux and macOS cases without touching six modules;doctorrunning privileged fix commands itself — it prints them.Closes #1350
🤖 Generated with Claude Code
Review follow-up
--strictcould never pass. RAM isESTIMATEDon every machine (no platform exposes a DRAM energy counter), and--strictfailed on anyESTIMATEDcomponent, so it exited 1 everywhere.--strictnow fails only on components that could have been measured, viadiagnostics.strict_failures(); RAM is exempt for the same reason an absent GPU isUNAVAILABLErather than a failure — the user has nothing to fix.test_doctor_strict_passes_on_a_machine_with_measured_cpu_and_gpuasserts exit 0 with a measured CPU + GPU and an estimated RAM, andtest_strict_failures_ignores_ram_but_not_the_cpuasserts an estimated CPU still fails.isinstanceinstead oftype(hw).__name__. The module already reads those classes' private attributes, so it now imports them and dispatches onisinstance; a rename fails at import instead of silently dropping a component from the report. The test fixtures build real (bare) hardware instances accordingly.allow_multiple_runs=True. Without it, a config withallow_multiple_runs = falseplus a live run makes__init__return early, leaving_hardware_initializedunset and_ensure_hardware_ready()raisingAttributeError— exactly when someone would reach fordoctor. Covered bytest_doctor_allows_multiple_runs.doctordoes not reconfigure a caller's logger.