From 4ded365124c3a63323c8a91c9a7a5b59ef920d48 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 1 Jul 2026 00:03:32 +0300 Subject: [PATCH] cpufreqd: only log transitions that actually happened; skip dwell on read-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In read-only mode (detected VM/QEMU/KVM) apply_pstate is a no-op so c.current_idx never advances. The previous log line was emitted whenever the *requested* target (n) differed from current_idx, regardless of whether the write actually fired — on QEMU that produced thousands of P0->P1 lines per boot even though no transition ever took place. Gate the info!() on whether current_idx actually changed. Also skip the dwell accumulation entirely on read-only hosts: writes cannot take effect, so the hysteresis counter is meaningless. The governor still tracks the target so the load value reflects real demand, but no work fires per poll. Closes Phase H of the LG Gram 16 (2025) S/P-state work. --- .../system/cpufreqd/source/src/main.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/local/recipes/system/cpufreqd/source/src/main.rs b/local/recipes/system/cpufreqd/source/src/main.rs index 6830a88ac7..8ea55d58e2 100644 --- a/local/recipes/system/cpufreqd/source/src/main.rs +++ b/local/recipes/system/cpufreqd/source/src/main.rs @@ -463,7 +463,10 @@ fn main() { // P0->P1->P0 oscillation on idle systems (QEMU and // real hardware with stable 0% load) where the governor // would otherwise toggle the state every poll cycle. - if n != c.current_idx { + // On read-only hosts (detected VM/QEMU) writes cannot + // take effect, so there is no point accumulating dwell + // — skip the check entirely. + if !c.read_only && n != c.current_idx { if n == c.dwell_target { c.dwell = c.dwell.saturating_add(1); } else { @@ -474,22 +477,28 @@ fn main() { continue; // not enough polls at this target yet } } else { - // Same state as last poll: reset dwell counter (no transition - // was requested so dwell stays at 0). + // Same state as last poll (or read-only host): reset + // dwell counter (no transition was requested so dwell + // stays at 0). c.dwell = 0; } if n != c.current_idx && n < c.pstates.len() { + let prev_idx = c.current_idx; let prev_freq = c.pstates[c.current_idx].freq_khz; let next_freq = c.pstates[n].freq_khz; let l_pct = l * 100.0; match c.mode { PstateMode::Hwp => { apply_pstate(c, n); - info!("CPU{} HWP→{}% ({}→{} kHz, load={:.0}%)", c.id, c.hwp_max.saturating_sub(n as u8 * (c.hwp_max - c.hwp_min) / c.pstates.len().saturating_sub(1).max(1) as u8), prev_freq, next_freq, l_pct); + if c.current_idx != prev_idx { + info!("CPU{} HWP→{}% ({}→{} kHz, load={:.0}%)", c.id, c.hwp_max.saturating_sub(n as u8 * (c.hwp_max - c.hwp_min) / c.pstates.len().saturating_sub(1).max(1) as u8), prev_freq, next_freq, l_pct); + } } PstateMode::LegacyPerfCtl => { apply_pstate(c, n); - info!("CPU{}: P{}→P{} ({}→{} kHz, load={:.0}%)", c.id, c.current_idx, n, prev_freq, next_freq, l_pct); + if c.current_idx != prev_idx { + info!("CPU{}: P{}→P{} ({}→{} kHz, load={:.0}%)", c.id, prev_idx, n, prev_freq, next_freq, l_pct); + } } } }