mlco2 / mlco2/codecarbon

ApplePowermetrics._setup_cli silently succeeds on Intel Macs

Open
#1,313 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.9k
Forks
323
Avg merge
1d 12h
Merged PRs (30d)
12

Description

Problem

ApplePowermetrics._setup_cli() is meant to validate that powermetrics can be used, but on an Intel Mac it falls through all of its branches and returns without either assigning self._cli or raising. As a result ApplePowermetrics() succeeds on non-Apple-Silicon hardware, is_powermetrics_available() returns True whenever a passwordless sudo rule exists, and ResourceTracker ends up registering an AppleSiliconChip for a machine that has no Apple Silicon chip. The measurements it then reports come from a code path that was never intended for that hardware.

The same function also crashes with an unexpected AttributeError when detect_cpu_model() returns None, which the broad except Exception in is_powermetrics_available() turns into a misleading "Not using PowerMetrics" debug line, hiding a genuine cpuinfo failure.

Reproduction

from unittest import mock
from codecarbon.core.powermetrics import ApplePowermetrics

with mock.patch("codecarbon.core.powermetrics.sys.platform", "darwin"), \
     mock.patch("codecarbon.core.powermetrics.detect_cpu_model",
                return_value="Intel(R) Core(TM) i7-9750H"):
    pm = ApplePowermetrics()   # succeeds, should not
    pm._cli                    # AttributeError

Root cause

  • codecarbon/core/powermetrics.py:117_setup_cli() has no terminal else for the "darwin but not Apple" case, so it returns silently.
  • codecarbon/core/powermetrics.py:122cpu_model.startswith(...) on the Optional[str] returned by codecarbon/core/util.py:77.
  • codecarbon/core/powermetrics.py:141_log_values() hardcodes "powermetrics" in the argv instead of using self._cli, which is why the missing assignment never surfaced as an error; the validation is effectively dead for its only caller.

Two smaller defects in the same argv:

  • codecarbon/core/powermetrics.py:146 — a stray "" is passed to powermetrics as a positional argument. Harmless on current macOS, but it is unintentional and a stricter parser would reject it.
  • codecarbon/core/powermetrics.py:156subprocess.call has no timeout, so a hung powermetrics blocks the measurement thread indefinitely.

Expected vs actual

Expected: on a Mac that is not Apple Silicon, _setup_cli() raises SystemError, is_powermetrics_available() returns False, and ResourceTracker falls through to Intel Power Gadget or the CPU-load fallback as _try_platform_cpu_backend (codecarbon/core/resource_tracker.py:225) intends.

Actual: ApplePowermetrics() is constructed successfully, powermetrics is selected, and an AppleSiliconChip is registered on Intel hardware. With detect_cpu_model() returning None, an AttributeError is swallowed and reported as powermetrics simply being unavailable.

Note for the changelog: machines that were accidentally using powermetrics on Intel Macs will change tracking method after this fix.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in codecarbon/core/powermetrics.py at _setup_cli(), is_powermetrics_available(), and _log_values(), then inspect detect_cpu_model() in codecarbon/core/util.py and _try_platform_cpu_backend in codecarbon/core/resource_tracker.py. Reproduce the Intel and None CPU-model cases from the issue, then verify that the expected fallback behavior and powermetrics invocation are covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, python
Domain
backend, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.