docs/images/cpu_fallback.png illustrates the CPU backend selection ladder. That ladder was corrected in #1377 after it was found not to match codecarbon/core/resource_tracker.py, and the diagram illustrates the old, incorrect version. #1377 therefore removed the reference to it from docs/explanation/methodology.md rather than ship a diagram contradicting the prose beside it.
The image file is still in the repository and is now unreferenced. It should be redrawn rather than quietly orphaned — a decision tree is the right form for this content, and the table that replaced it is harder to scan.
What the diagram should show
The real selection order, from resource_tracker.py:249-279, first match wins:
force_cpu_power set → fixed constant. This is the branch most worth making visually obvious: it skips every platform backend, so RAPL is not consulted even when available (:255-260, guard at :272).
force_mode_cpu_load set, psutil present, TDP known → cpu_load (:263-270)
- Linux + RAPL readable → intel_rapl (
:223-225)
- macOS + Apple Silicon +
psutil → cpu_load (:228-230) — note this precedes powermetrics
- macOS + Apple Silicon + no
psutil + powermetrics → powermetrics (:231-233)
- macOS + Intel + Power Gadget → intel_power_gadget (
:234-236)
- macOS + Intel + powermetrics → powermetrics (
:237-239)
- Windows + EMI → windows_emi (
:241-243)
- Windows + Power Gadget → intel_power_gadget (
:244-246)
- otherwise,
psutil present → cpu_load (:179-190, :201-212)
- otherwise → constant (
:191-198, :213-218)
Two things the old diagram got wrong and the new one must get right:
- cpu_load is preferred over constant whenever
psutil is present. constant mode is the no-psutil path only.
- On Apple Silicon,
powermetrics is effectively unreachable, because step 4 fires before step 5 and psutil is a hard dependency.
Also worth showing
The TDP resolution that feeds the two estimation modes (core/cpu.py:1002-1032):
- registry hit → registry TDP
- model detected, absent from registry,
psutil present → threads × DEFAULT_POWER_PER_CORE (4 W, cpu.py:29)
- otherwise →
POWER_CONSTANT (85 W, hardware.py:23)
and that the resulting TDP is consumed by two different curves — cubic with a 10% floor in machine mode, linear in process mode (hardware.py:287-288 and :346).
That may be more than one diagram can carry legibly; splitting into "which backend" and "how the TDP becomes watts" is fine.
Acceptance
- The diagram matches
resource_tracker.py at the commit it lands on.
- It is referenced from
docs/explanation/methodology.md#which-backend-gets-chosen.
- Ideally it is generated from a text source (Mermaid or Graphviz) checked into the repo, so the next correction to the ladder is a diff rather than a redraw in an image editor.
Context: #1377.
docs/images/cpu_fallback.pngillustrates the CPU backend selection ladder. That ladder was corrected in #1377 after it was found not to matchcodecarbon/core/resource_tracker.py, and the diagram illustrates the old, incorrect version. #1377 therefore removed the reference to it fromdocs/explanation/methodology.mdrather than ship a diagram contradicting the prose beside it.The image file is still in the repository and is now unreferenced. It should be redrawn rather than quietly orphaned — a decision tree is the right form for this content, and the table that replaced it is harder to scan.
What the diagram should show
The real selection order, from
resource_tracker.py:249-279, first match wins:force_cpu_powerset → fixed constant. This is the branch most worth making visually obvious: it skips every platform backend, so RAPL is not consulted even when available (:255-260, guard at:272).force_mode_cpu_loadset,psutilpresent, TDP known → cpu_load (:263-270):223-225)psutil→ cpu_load (:228-230) — note this precedes powermetricspsutil+ powermetrics → powermetrics (:231-233):234-236):237-239):241-243):244-246)psutilpresent → cpu_load (:179-190,:201-212):191-198,:213-218)Two things the old diagram got wrong and the new one must get right:
psutilis present.constantmode is the no-psutil path only.powermetricsis effectively unreachable, because step 4 fires before step 5 andpsutilis a hard dependency.Also worth showing
The TDP resolution that feeds the two estimation modes (
core/cpu.py:1002-1032):psutilpresent →threads × DEFAULT_POWER_PER_CORE(4 W,cpu.py:29)POWER_CONSTANT(85 W,hardware.py:23)and that the resulting TDP is consumed by two different curves — cubic with a 10% floor in machine mode, linear in process mode (
hardware.py:287-288and:346).That may be more than one diagram can carry legibly; splitting into "which backend" and "how the TDP becomes watts" is fine.
Acceptance
resource_tracker.pyat the commit it lands on.docs/explanation/methodology.md#which-backend-gets-chosen.Context: #1377.