Skip to content

Conversation

@arighi
Copy link
Contributor

@arighi arighi commented May 27, 2025

Introduce an option to throttle the CPUs, forcing them to periodically stay idle for a certain amount of time every time slice period.

This option can help extend battery life on portable devices, reduce heating, fan noise and overall energy consumption (disabled by default).

The mechanism is implemented using a BPF timer configured with a duty cycle that defines alternating execution and idle intervals. The timer regularly preempts all the CPUs (SCX_KICK_PREEMPT), allowing them to enter the idle state. After the idle period, it wakes them up using SCX_KICK_IDLE to resume execution for the next runtime interval.

This allows to inject idle phases interleaved with active runtime across all CPUs, effectively throttling their activity.

Test results

Hardware:

  • CPU: AMD Ryzen AI 9 HX 370 w/ Radeon 890M

    • cpufreq: amd_pstate with energy_performance_preference=power
  • Test: WebGL acquarium / 15K fishes (https://webglsamples.org/aquarium/aquarium.html)

  • Power consumption (measured using turbostat): $ turbostat --header_iterations 5 -S -s PkgWatt,CorWatt

  • Result (fps / W):

scx_bpfland               |   fps    | CorWatt | PkgWatt
--------------------------|----------|---------|--------
 -m all                   | 100–110  | 18.51   | 27.86
 -m powersave             |   80–85  |  9.31   | 19.00
 -m powersave -t 5000     |   65–68  |  7.58   | 15.34
 -m powersave -t 10000    |   25-30  |  2.16   |  7.11
 -m powersave -t 50000    |   10–11  |  0.86   |  4.59

In this scenario, injecting 10ms idle cycles resulted in ~74.5% power savings (theoretically extending battery life by nearly 4x), while maintaining reasonable system responsiveness (25–30 fps in the WebGL aquarium benchmark).

[ fixed "devices" spelling mistake noticed by @1Naim ]

Introduce an option to throttle the CPUs, forcing them to periodically
stay idle for a certain amount of time every time slice period.

This option can help extend battery life on portable devices, reduce
heating, fan noise and overall energy consumption (disabled by default).

The mechanism is implemented using a BPF timer configured with a duty
cycle that defines alternating execution and idle intervals. The timer
regularly preempts all the CPUs (SCX_KICK_PREEMPT), allowing them to
enter the idle state. After the idle period, it wakes them up using
SCX_KICK_IDLE to resume execution for the next runtime interval.

This allows to inject idle phases interleaved with active runtime across
all CPUs, effectively throttling their activity.

Test results
============

Hardware:
 - CPU: AMD Ryzen AI 9 HX 370 w/ Radeon 890M
   - cpufreq: amd_pstate with energy_performance_preference=power

- Test: WebGL acquarium / 15K fishes
  (https://webglsamples.org/aquarium/aquarium.html)

- Power consumption (measured using turbostat):
  $ turbostat --header_iterations 5 -S -s PkgWatt,CorWatt

- Result (fps / W):

scx_bpfland               |   fps    | CorWatt | PkgWatt
--------------------------|----------|---------|--------
 -m all                   | 100–110  | 18.51   | 27.86
 -m powersave             |   80–85  |  9.31   | 19.00
 -m powersave -t 5000     |   65–68  |  7.58   | 15.34
 -m powersave -t 10000    |   25-30  |  2.16   |  7.11
 -m powersave -t 50000    |   10–11  |  0.86   |  4.59

In this scenario, injecting 10ms idle cycles resulted in ~74.5% power
savings (theoretically extending battery life by nearly 4x), while
maintaining reasonable system responsiveness (25–30 fps in the WebGL
aquarium benchmark).

[ fixed "devices" spelling mistake noticed by @1Naim ]

Signed-off-by: Andrea Righi <arighi@nvidia.com>
@arighi arighi requested review from hodgesds, htejun and multics69 May 27, 2025 16:54
@hodgesds
Copy link
Contributor

It may be useful to allow per CPU throttling in the timer rather than all CPUs. Then you could keep a cpumask of throttled CPUs and be less aggressive with idle CPU selection. Maybe something for the future though as this looks fine as is.

@arighi
Copy link
Contributor Author

arighi commented May 27, 2025

It may be useful to allow per CPU throttling in the timer rather than all CPUs. Then you could keep a cpumask of throttled CPUs and be less aggressive with idle CPU selection. Maybe something for the future though as this looks fine as is.

I like the idea of using a cpumask to throttle specific CPUs, it could be even used as a way to artificially simulate e-cores / p-cores. Will definitely add that, thanks for the suggestion!

@arighi arighi added this pull request to the merge queue May 27, 2025
Merged via the queue into main with commit 656ab0b May 27, 2025
32 checks passed
@arighi arighi deleted the bpfland-throttle branch May 27, 2025 18:52
@multics69
Copy link
Contributor

This is an interesting idea! I see throttling would be useful when a game already achieves high-enough FPS (e.g., 120 FPS).

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.

4 participants