Skip to content

Report NPU power and per-column utilization from the sensor query - #1

Open
hiasihaho wants to merge 1 commit into
mcolsen:mainfrom
hiasihaho:sensors
Open

Report NPU power and per-column utilization from the sensor query#1
hiasihaho wants to merge 1 commit into
mcolsen:mainfrom
hiasihaho:sensors

Conversation

@hiasihaho

Copy link
Copy Markdown

The driver exposes a sensor block via GET_INFO param 4 (DRM_AMDXDNA_QUERY_SENSORS) that nputop wasn't reading: NPU package power and per-column busy percentage, both sourced from amd_pmf NPU metrics. This adds the query and surfaces both.

Per-column busy is the utilization signal the TUI was missing. As the README already notes, TOPS is a capacity metric — it's derived from the current clock, so it reads high whenever power management has clocked the NPU up, whether or not there's work queued. On my machine during an 8B decode it read TOPS 41/58 while the array was 99% busy, so the headline bar was showing ~70% for a saturated NPU. (It can also exceed tops_max; I've seen 59/58.)

So: busy percentage becomes the headline bar when available, TOPS stays as text next to Tasks, and a per-column sparkline shows whether a workload spans the array or sits in a corner. Power lands in the existing Power panel as a watts reading.

Display

Idle:

╭─ Utilization ───────────╮╭─ Clocks ────────────────╮╭─ Power ────────────────╮
│ 0 % busy                ││ MP-NPU Clock   66 MHz   ││ Draw  0.00 W           │
│ ░░░░░░░░░░░░░░░░        ││ H Clock     104 MHz     ││ Mode  DEFAULT          │
│ cols ▁▁▁▁▁▁▁▁           ││ max        1800 MHz     ││ NPU   active           │
│ Tasks 0/16   TOPS 3/58  ││                         ││ up    21h 29m          │
╰─────────────────────────╯╰─────────────────────────╯╰────────────────────────╯

Under a FastFlowLM 8B decode:

╭─ Utilization ────────────╮╭─ Clocks ─────────────────╮╭─ Power ──────────────────╮
│ 99 % busy                ││ MP-NPU Clock  975 MHz    ││ Draw  0.78 W             │
│ █████████████████████████││ H Clock    1267 MHz      ││ Mode  DEFAULT            │
│ cols ████████            ││ max        1800 MHz      ││ NPU   active             │
│ Tasks 4/16   TOPS 41/58  ││                          ││ up    21h 29m            │
╰──────────────────────────╯╰──────────────────────────╯╰──────────────────────────╯

Power tracked 0.78–1.9 W across runs depending on clock state.

Two ABI details worth recording

The driver truncates the sensor array silently instead of returning ENOSPC. aie2_query_sensors decrements buffer_size per sensor written and jumps to out: when the next one won't fit, where it sets args->buffer_size = sensors_count * sizeof(sensor). A too-small buffer therefore looks like "fewer sensors", not an error. _get_info assumes a fixed-size reply, so I added _get_info_sized(), which oversizes the buffer and bounds parsing by the byte count written back.

The raw value scales by 10**unitm to reach the SI base unit. The header comment says "translates value into the correct unit via pow(10, unitm) * value", which taken together with units = "mW" would make the power reading 1.887 mW under load. The driver assigns sensor.input = npu_metrics.npu_power (mW) with unitm = -3, so the scaled value is watts and units describes the raw field. Column utilization is consistent with this: unitm = 0, units = "%". Flagging it because it's a judgement call and the header comment reads the other way.

Degradation

The query needs HAVE_7_0_amd_pmf_get_npu_data in the driver build, and AMD's docs say power reporting is unsupported on PHX/HPT. So an ioctl failure is treated as "no sensors" and the panel falls back to the previous TOPS bar, titled TOPS & Tasks as before. All-zero readings are a legitimate idle result and are shown as such rather than being mistaken for missing sensors.

Panels gain a line when sensors are present and Rich sizes each independently, so they're pinned to a common height to keep the borders aligned.

Testing

Strix Halo, firmware 1.1.2.65, Fedora 43, kernel 7.1.0-rc5, AMD out-of-tree amdxdna (xrt-amdxdna 2.21.75) via DKMS.

  • Live at idle and under FastFlowLM load, at wide (120 col) and tiny (58 col) breakpoints.
  • All three degradation paths exercised by stubbing query_sensors: returns None, power-without-columns, and columns-without-power. Each falls back correctly and keeps borders aligned.

I can't test the PHX/HPT or no-PMF paths on this hardware — only that the fallback renders when the query is stubbed out.

🤖 Generated with Claude Code

https://claude.ai/code/session_016G1XTP4RxcrBsyrrDxMxPM

The driver exposes a sensor block via GET_INFO param 4 that nputop was not
reading: NPU package power and per-column busy percentage, both sourced from
amd_pmf NPU metrics.

Per-column busy is the utilization signal the TUI was missing. TOPS tracks
the clock rather than the load, so it reads high whenever power management
has clocked the NPU up, whether or not work is queued -- as the README
already noted, it is a capacity metric. Make busy percentage the headline
bar when it is available, keep TOPS as text alongside it, and add a
per-column sparkline so it is visible when a workload occupies only part of
the array. Power lands in the existing Power panel as a watts reading.

The query needs HAVE_7_0_amd_pmf_get_npu_data in the driver and is
unsupported on PHX/HPT, so treat an ioctl failure as "no sensors" and fall
back to the previous TOPS bar. All-zero readings are a legitimate idle
result and are shown as such.

Two details of the kernel ABI worth recording: the driver truncates the
sensor array silently instead of returning ENOSPC, so the buffer is
oversized and the written byte count is what bounds parsing; and the raw
value scales by 10**unitm to reach the SI base unit, which turns the power
sensor's mW/-3 into watts.
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.

1 participant