Skip to content

thermald: adaptive: support more than one GDDV virtual sensor - #603

Open
Scrimas wants to merge 1 commit into
intel:masterfrom
Scrimas:adaptive-multi-virtual-sensor
Open

Scrimas wants to merge 1 commit into
intel:masterfrom
Scrimas:adaptive-multi-virtual-sensor

Conversation

@Scrimas

@Scrimas Scrimas commented Oct 2, 2026 •

Copy link
Copy Markdown

Problem

cthd_gddv keeps a single vscts_name and appends every VSCT/VSPT entry it parses to the same two vectors. When a platform defines more than one virtual sensor participant, they are all merged into one cthd_sensor_virtual named after the last one parsed, and the other names never get a zone.

On the Samsung Galaxy Book5 Pro 360 (NP960QHA, Core Ultra 7 256V / Lunar Lake, BIOS P17ALY.390.260616.03) the data vault defines two virtual sensors, VR1.D0 and VR2.D0. The "High" adaptive target (matched with the performance platform profile, Oem0 = 21) installs PSVT high_vr2, whose only entry targets VR1:

source:\_SB_.PC00.TCPU target:\_UP_.VR1 priority:1 sample_period:50 temp:50 domain:9 ...

With thermald 2.5.13, thermald --adaptive --no-daemon --loglevel=debug on performance:

[INFO]..vsct dump begin [VR2.D0]
[INFO]Found virtual sensor [VR2.D0]
[DEBUG]zone VR2 bounded
[DEBUG]Condition Set matched:2 target:14
[INFO]set_int3400 target high_vr2
[WARN]Unable to find a zone for VR1
[WARN]Adaptive policy couldn't create any zones
[WARN]Possibly some sensors in the PSVT are missing
[WARN]Restart in non adaptive mode via systemd

The "merged" VR2 sensor contains the targets of both participants (TCPU, SNS1, SNS2, SNS3 from VR1 plus SNS2 and the constant from VR2), and both polling tables. thermald then writes ignore_adaptive and exits. This CPU model is only supported in adaptive mode, so the restart leaves the machine with no thermald at all. Every other target on this platform (optimize, quiet, silent, tablet, inbag) uses SNS1 and works, so the failure only shows up on the performance profile, which TLP and power-profiles-daemon select on AC by default.

Fix

  • Parse VSCT and VSPT entries per participant into a vsensor list (name, vscts, vspts), keyed by the participant name (VR1.D0, VR2.D0).
  • Create one virtual sensor and one zone per entry. The existing setup code moved unchanged into install_virtual_sensor(). A sensor that fails to set up is skipped instead of stopping the remaining ones.
  • A VSPT without a participant name (stored under the old default name vsct) is still applied to any virtual sensor without its own polling table. A data vault with a single virtual sensor produces the same sensor and zone as before.

git diff -w: +98 / −39. The rest is re-indentation from moving the block into the new function.

Testing

Same machine, kernel 7.2.8, patched build run from the build tree:

  • performance profile: ran the full 30 s, no exit, no ignore_adaptive:
    [INFO]..vsct dump begin [VR1.D0]
    [INFO]..vsct dump begin [VR2.D0]
    [INFO]Found virtual sensor [VR1.D0]
    [DEBUG]zone VR1 bounded
    [INFO]Found virtual sensor [VR2.D0]
    [DEBUG]zone VR2 bounded
    [DEBUG]Condition Set matched:2 target:14
    [INFO]set_int3400 target high_vr2
    
    PL1 30 W and its time window were applied, and restored on exit.
  • balanced → performance → balanced while running (45 s): target switched Default/optimize → High/high_vr2 → Default/optimize. No exit, and power limits were restored on exit.
  • VR1.D0 gets 4 VSCT targets plus its own VSPT (30/40/45 °C). VR2.D0 gets 2 targets plus its own VSPT (17/24 °C).
  • Under High, zone VR1 gets a passive trip at 50 °C bound to rapl_controller_mmio, plus a polling trip at 45 °C. No PSVT or condition on this platform references VR2, so its zone has no trip.
  • Load test on performance (stress-ng --cpu 8, 280 s): PL1 held at 30 W (High's PL1MAX; it was 34 W before thermald), with the package at ~30 W, ~3.9 GHz and TCPU ~80 °C. VR1 as computed by thermald peaked at ~41 °C, so the 50 °C trip was not reached and I could not observe it firing. That trip and cooling device path is existing code that this change only makes reachable.
  • make and make clang-tidy are clean for the changed lines.

Not tested: a platform with a single virtual sensor (I don't have one). That path creates exactly one vsensor entry and goes through the same calls as before.

Attached:

  • samsung_np960qha_data_vault.zip: this machine's data vault, as the raw .bin and as an od -x .hex for the GDDV_LOAD_FROM_FILE test loader.
  • thermald-logs.zip: full --loglevel=debug logs of each run above (stock 2.5.13 on performance, patched on performance, the profile-switch run, the stress-ng run, and its 5 s samples of temperatures, PL1, package power and clock).

I prefer to be honest and disclose that this change was written with the help of an AI coding assistant (Claude). I reviewed it and tested it on the affected hardware as described above.

thermald-logs.zip
samsung_np960qha_data_vault.zip

The GDDV parser kept a single vscts_name and appended every VSCT and
VSPT entry it found to the same two vectors. On platforms that define
more than one virtual sensor participant, all of them were merged into
one cthd_sensor_virtual named after the last one parsed, and the others
never got a zone.

Samsung Galaxy Book5 Pro 360 (NP960QHA, Lunar Lake) defines VR1.D0 and
VR2.D0. Its "High" adaptive target, selected with the performance
platform profile (Oem0 = 21), installs PSVT high_vr2, whose only entry
targets VR1. With VR1 folded into VR2, install_passive() logs "Unable
to find a zone for VR1", no zone is created, and thermald writes
ignore_adaptive and exits, leaving the platform without adaptive
control.

Store VSCT and VSPT entries per participant in a vsensor list and
create one virtual sensor and zone for each. A VSPT without a
participant name still applies to sensors that have no polling table of
their own, and a GDDV with a single virtual sensor produces the same
sensor and zone as before.

Signed-off-by: Scrimas <isma.ph@proton.me>
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