On 2026/9/18 03:34, Rafael J. Wysocki (Intel) wrote: > On Wed, Jul 29, 2026 at 8:16 AM Yaxiong Tian <[email protected]> wrote: >> cpuidle_governor_latency_req() is evaluated on every idle-state >> selection. It aggregates the per-CPU resume latency with the global >> CPU latency and wakeup latency QoS limits > True. > >> by repeatedly calling >> get_cpu_device() and pm_qos_read_value() cpu_latency_qos_limit() >> cpu_wakeup_latency_qos_limit(). > I would say "every time" rather than "repeatedly", but fair enough. > > However, those functions don't do anything expensive except for > defensive checks that can be omitted. Have you tried to omit them? I haven't tried that, but I found that function_graph may introduce measurement errors, especially for very short functions. > >> Use ftrace's function_graph, we can see: >> parent: do_idle >> parent_total_ns: 36671010505 >> parent_count: 5994 >> >> SYMBOL TIME_NS %ROOT >> %PARENT COUNT >> -------------------------------------------------------------------------------------------------- >> do_idle 36671010505 100.00% >> 100.00% 5994 >> cpuidle_idle_call 35566528731 96.99% >> 96.99% 8570 >> call_cpuidle 35476606844 96.74% >> 99.75% 8561 >> cpuidle_enter 35472932468 96.73% >> 99.99% 8526 >> cpuidle_select 52097031 0.14% >> 0.15% 8580 >> menu_select 49555181 0.14% >> 95.12% 8580 >> tick_nohz_get_sleep_length 28843887 0.08% >> 58.21% 8570 >> cpuidle_governor_latency_req 9567488 0.03% >> 19.31% 8580 >> tick_nohz_tick_stopped 2057031 0.01% >> 4.15% 15695 >> cpuidle_reflect 11427201 0.03% >> 0.03% 8561 >> menu_reflect 6579506 0.02% >> 57.58% 8526 >> tick_nohz_idle_got_tick 2231559 0.01% >> 33.92% 8526 >> __sysvec_apic_timer_interrupt 105520 0.00% >> 0.92% 3 >> tick_nohz_idle_stop_tick 8279641 0.02% >> 0.02% 1475 >> ---- skip >> >> The majority of the time spent in cpuidle_enter for CPUs entering >> idle state has already been charged to the idle path. Among the >> remaining contributors, cpuidle_governor_latency_req() accounts >> for a non-negligible portion of the overall latency. >> >> Under the menu governor this shows up hot: ftrace data shows, >> cpuidle_governor_latency_req() accounts for about 19.9% of >> menu_select() time (~1.9 us/call). After caching the aggregated >> value per CPU and invalidating via QoS notifiers, that share drops to >> about 4.2% (~0.3 us/call), roughly a 6x reduction on this path. > Is there any real-world workload in which that difference is actually visible? Sorry, I only tested it under no load.
> >> The ftrace data before and after the optimization is shown below: >> 1) original >> parent: menu_select >> parent_total_ns: 160492937 >> parent_count: 16718 >> >> SYMBOL TIME_NS %ROOT >> %PARENT COUNT >> -------------------------------------------------------------------------------------------------- >> menu_select 160492937 100.00% >> 100.00% 16718 > Where did you lose menu_update()? Because menu_update() was optimized away by the compiler, it can't be seen in /proc/kallsyms, so it won't be traced by ftrace either. > >> tick_nohz_get_sleep_length 100262940 62.47% >> 62.47% 16698 >> tick_nohz_next_event 67891299 42.30% >> 67.71% 16689 >> rcu_needs_cpu 2825649 1.76% >> 4.16% 16689 >> timekeeping_max_deferment 2380377 1.48% >> 3.51% 15296 >> hrtimer_next_event_without 17865162 11.13% >> 17.82% 15296 >> hrtimer_bases_next_event_without 2707631 1.69% >> 15.16% 15296 >> _raw_spin_lock_irqsave 2461132 1.53% >> 13.78% 15296 >> native_queued_spin_lock_slowpath 177 0.00% >> 0.01% 1 >> _raw_spin_unlock_irqrestore 2364647 1.47% >> 13.24% 15296 >> can_stop_idle_tick 2906072 1.81% >> 2.90% 16698 >> cpuidle_governor_latency_req 31988150 19.93% >> 19.93% 16718 >> get_cpu_device 4122502 2.57% >> 12.89% 16718 >> pm_qos_read_value 3427318 2.14% >> 10.71% 16718 >> cpu_latency_qos_limit 3005804 1.87% >> 9.40% 16718 >> cpu_wakeup_latency_qos_limit 3005475 1.87% >> 9.40% 16718 >> tick_nohz_tick_stopped 4551981 2.84% >> 2.84% 29496 >> >> %ROOT = share of menu_select; %PARENT = share of immediate caller (inclusive) >> >> 2) post-optimized >> parent: menu_select >> parent_total_ns: 55428604 >> parent_count: 7626 >> >> SYMBOL TIME_NS %ROOT >> %PARENT COUNT >> -------------------------------------------------------------------------------------------------- >> menu_select 55428604 100.00% >> 100.00% 7626 > And here? > >> tick_nohz_get_sleep_length 37464607 67.59% >> 67.59% 7544 >> tick_nohz_next_event 24076913 43.44% >> 64.27% 7522 >> get_next_timer_interrupt 16332381 29.47% >> 67.83% 5854 >> rcu_needs_cpu 1489633 2.69% >> 6.19% 7522 >> timekeeping_max_deferment 870851 1.57% >> 3.62% 5586 >> hrtimer_next_event_without 6140153 11.08% >> 16.39% 5586 >> hrtimer_bases_next_event_without 979000 1.77% >> 15.94% 5586 >> _raw_spin_lock_irqsave 808786 1.46% >> 13.17% 5586 >> _raw_spin_unlock_irqrestore 785518 1.42% >> 12.79% 5586 >> can_stop_idle_tick 1583137 2.86% >> 4.23% 7544 >> cpuidle_governor_latency_req 2321119 4.19% >> 4.19% 7626 >> tick_nohz_tick_stopped 1863015 3.36% >> 3.36% 12751 >> >> %ROOT = share of menu_select; %PARENT = share of immediate caller (inclusive) >> >> This series: >> - patch1~pathc3: Add QoS notifiers-related infrastructure and updates to >> latency_req_gen. >> - patch4: Implement QoS constraint for cache-aggregated governor latency >> - patch5: add latency_req QoS idle-state selection test >> - patch6: add idle-state disable selftest > So this adds two per-CPU variables and a ton of extra complexity to > optimize the case in which the majority of the governor computations > aren't actually done. > > I'm totally unconvinced. I agree, it doesn't seem worth the effort. > > Thanks!

