Skip to content

soc: apple: clpc, drm/asahi: g17: busy-share memory floor and light effort for T6041 - #1369

Open
AxxzyWasTaken wants to merge 5 commits into
aurora-silicon:integration/aurorafrom
AxxzyWasTaken:max-gpu-power-v2
Open

AxxzyWasTaken wants to merge 5 commits into
aurora-silicon:integration/aurorafrom
AxxzyWasTaken:max-gpu-power-v2

Conversation

@AxxzyWasTaken

@AxxzyWasTaken AxxzyWasTaken commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Replaces #1089, rebased onto current integration/aurora as requested. The review asked for a reworded commit message ("at least 400 ms"), which needs new history, so this is a new branch; #1089's branch is left as it was.

Lowers power on the M4 Max in everyday use. On T6040/T6041, any reported GPU work holds the top memory and fabric floor, and the GPU runs at full effort for quiet work.

  • CLPC: the GPU driver reports its busy share, and the floor follows a per-SoC table in struct apple_clpc_hw (DCS 1, 2, 4, 5 and fabric 0, 0, 0, 2, split at gpu_busy_mid 160, gpu_busy_high 500 and gpu_busy_top 800 permille). Going down happens at least 400 ms after the last change. CPU map quarters now use 4.512 GHz for both clusters, and the T6040 map is lower.
  • G17: a light effort governor, half effort after four quiet windows, with separate entry and exit points. note_submission() no longer skips it.
M4 Max, AC, 120 Hz Old New
Scrolling 24.9 W 22.1 W
Page workload 23.84 W 22.73 W, score -0.9 %

Effort sweep on a 1080p30 clip: full 14.0 W, half 10.4 W.

Changes since #1089 (review by RyanTheTide):

  • gpu_busy_top, gpu_busy_high and gpu_busy_mid are apple_clpc_hw fields next to gpu_busy with the same values for T6040/T6041, no longer 0644 module parameters.
  • The commit message says the down-step happens at least 400 ms after the last change.
  • apple_clpc_status_show() reads gpu->busy, busy_valid and level under the lock and no longer calls apple_clpc_gpu_level(), so reading debugfs can't move the level.
  • tools/asahi/clpc-gpu-demand-tests.py extracts apple_clpc_gpu_level(), has a max_t macro and the new struct apple_clpc_gpu fields, and adds cases for no share reported, below gpu_busy_mid, between the thresholds, the 400 ms down-step hold and its restart, plus three negative controls.
  • Rebased over Neo ANE: hold DRAM and fabric floors while the engine runs, keep gating off back-to-back (MobileNet 2.3-2.5 -> 1.25-1.31 ms) #1137: struct apple_clpc_hw and the T6040 table keep both the ANE fields and the busy-share fields. The T6040 comments that said a busy CPU cluster or GPU work gets DCS 5 / fabric 2 now match the new tables. The CPU map is unchanged from soc: apple: clpc, drm/asahi: g17: busy-share memory floor and light effort for T604x #1089.
  • The G17 commit is unchanged.

Tested: the logic has been the daily setup on my M4 Max since 5 Nov (7.3.0), with no GPU recoveries from it. For this exact head: python3 -I tools/asahi/run-host-tests.py --only with clpc, usage, g15-queue-credit, asahi-m4 and g17 passes (35 runs), and the CLPC demand test passes with all 15 negative controls. drivers/soc/apple/clpc.o and drivers/gpu/drm/asahi/g17/clpc.o build with LLVM=1 W=1 with no new warnings. Not done: KUnit was not run, and before the rebase this head had not been booted.

Built and booted, 12 Nov (the whole kernel, Rust drm/asahi included): rebased onto integration/aurora c6e08489, where clpc.c and g17/mod.rs conflicted. The GPU demand takes the busy-share column but never goes below a chip's new .gpu minimum; note_submission() keeps the new note_waiters() call and takes its effort from submission_effort(). The CLPC demand test passes with all its negative controls. This code is my daily kernel now on the M4 Max, together with #1664: a deep sleep, a desktop logout after the wake, and a game session, with the g17_light_* parameters taking effect and no GPU errors or recoveries in the log.

Please check:

  • The CLPC table is shared with T6040, and I haven't tested an M4 Pro.
  • The light effort governor is in the shared G17 code, so it applies to other G17 SoCs too. aurora.g17_light_effort=0 turns it off. Tell me if you'd rather have it scoped to T604x.

@RyanTheTide

Copy link
Copy Markdown
Contributor

This no longer merges into integration/aurora: drivers/soc/apple/clpc.c conflicts with #1405 (T6050 CPU floor, merged as 1682b11). Please merge the current integration/aurora into the branch (or rebase) and keep both the T6050 floor and the T6041 busy-share path.

On T6040 and T6041 any reported GPU work holds the top memory and fabric
floor. At 120 Hz a scrolling browser keeps the GPU reported busy most of
the time for a few percent of real execution, so light desktop use pays
for the top DCS state.

Let the GPU driver report its busy share per window with
apple_clpc_gpu_set_busy() and pick the floor from a per-SoC table in
struct apple_clpc_hw: on T6040/T6041 DCS 1, 2, 4 or 5 and fabric 0, 0, 0
or 2, split at gpu_busy_mid (160), gpu_busy_high (500) and gpu_busy_top
(800) permille. A higher level applies at once. A lower one applies at
the first CLPC sample at least 400 ms after the last sample that asked
for the current level or a higher one, so the down-step happens at least
400 ms after the last change, later if the sampler runs late. A GPU that
reports no share, and every SoC without the table, keeps the top of the
map. The debugfs status shows the reported share and the current level
without moving it.

The CPU side had the same problem: a cluster at its own top speed asked
for DCS 5 and fabric 2 even when that was the E cluster. Take the map
quarters from 4.512 GHz for both clusters, and lower the T6040 map to
DCS 1, 1, 3, 4 with fabric 0. On the M4 Max on AC, compared with the old
table: scrolling 24.9 W to 22.1 W at 120 fps with no long frames, a page
workload 23.84 W to 22.73 W for 0.9 % less score.

The CLPC host demand test now covers the busy-share table, a GPU that
reports no share and the down-step hold.

Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
Sum the engine time every client is charged and report its share of a
200 ms window to CLPC, which then keeps the top memory and fabric floor
for GPU work that really is busy.

The same windows drive a light effort governor. Four quiet windows in a
row (under 35 % busy, no job of 3 ms or more) drop the firmware to half
effort, and 75 % busy or a 7 ms job goes back to full. Light effort runs
the same work about twice as long, so the way out sits at about twice
the way in, or work that fits light effort sticks at full. The share
sent to CLPC is doubled at full effort so one floor table fits both.

note_submission() returned effort_full, so the lockless path skipped the
governor. It now takes the slow path when the governor wants light.

g17_light_effort (65536 is full, 0 turns this off), g17_light_enter,
g17_light_exit, g17_light_job_enter_us and g17_light_job_exit_us are
runtime parameters. Effort sweep on the M4 Max with a 1080p30 clip: full
14.0 W, 32768 10.4 W, and below 50 % gained nothing.

Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>

@RyanTheTide RyanTheTide left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AxxzyWasTaken thanks for the rebase and the power numbers. Three things before this can go in:

  1. apple_clpc_hw_t6040 is also the M4 Pro's table. The CPU map change (DCS 1,1,3,4 and fabric 0,0,0,0 at the top, and level_khz for the E cluster) lowers the memory floor a busy CPU gets on the M4 Pro, where the comment above the table measures 237-242 GB/s at DCS 5 / fabric 2. Please give T6041 its own table and leave T6040 as it is, or add M4 Pro measurements. We can run the M4 Pro side if you split it.
  2. The light-effort governor is in the shared G17 code and on by default, so it also changes the A18 Pro and M4 Pro. A 120 fps game reads about a third busy, under the 350 entry point, and stays under the 750 exit point once it runs at half effort. Please scope it per SoC (match data, T6041 first) until it has frame-time results on games, not only power.
  3. Please replace the five g17_light_* module parameters with per-SoC values, as was done for the CLPC thresholds.

Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
…t effort to T6041

The M4 Pro shares the CLPC compatible and the G17 code with the M4 Max,
so both changes reached it unmeasured.

Give T6041 its own CLPC table, picked on an "apple,t6041" machine, and
leave apple_clpc_hw_t6040 as integration/aurora has it. Move the light
effort thresholds from five module parameters into the per-SoC G17
Config, set only for T6041; other SoCs run every submission at full
effort and report the busy share unscaled.

Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
@AxxzyWasTaken

Copy link
Copy Markdown
Contributor Author

Thanks. All three are in 33db416, on top of a merge of the current integration/aurora (e6588ee, clean).

  1. T6041 has its own CLPC table. apple_clpc_hw_t6040 is back to exactly what integration/aurora has, so the M4 Pro keeps DCS 1,2,5,5 / fabric 0,1,2,2 and its ANE cluster floor. The M4 Max shares the apple,t6041-clpc compatible, so apple_clpc_machine_hw() picks the new apple_clpc_hw_t6041 on an "apple,t6041" machine. That table carries the CPU map, level_khz, the busy-share ladder, the Low Power Mode values and the ANE rails, with the J616c measurements in its comment. It leaves out the ANE cluster floor, which was measured on the M4 Pro only.
  2. Light effort is per SoC. The G17 Config has a new light_effort: Option<power::LightEffort>. Only T6041's base config sets it, which covers both of its firmware builds. T6040, T6050, T8140 and T8142 have None, so every submission runs at full effort there and the busy share is reported unscaled.
  3. No module parameters. The five g17_light_* parameters are gone. The thresholds come from that per-SoC value, and power::configure_light() loads them when the GPU starts.

Tested: Image and modules build at W=1 with no new warnings in drivers/soc/apple or drivers/gpu/drm/asahi, and tools/asahi/clpc-gpu-demand-tests.py passes, with the busy-share test now on the T6041 table. Not run on hardware yet, and there are no frame-time results for light effort yet, so it stays limited to T6041 until I have those.

@RyanTheTide RyanTheTide left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AxxzyWasTaken thanks, this addresses all three points. The T6040 table matches the base again, the T6041 table is picked by machine compatible, and light effort is off everywhere except T6041 with no module parameters. Two things before merge:

  1. Please boot this head (33db416) on the M4 Max and post the scrolling power and a GPU smoke result. The light-effort and table code moved since your last numbers.
  2. Small race in report_busy(): two submitters that both see elapsed >= BUSY_WINDOW_NS each swap BUSY_WINDOW_TOTAL, and the second one reports about 0 permille for the same window, which on T6041 also counts as a quiet window. A compare_exchange on BUSY_WINDOW_START (only the winner reports) closes it. Optional: clearing busy_valid when the GPU goes inactive, so a new burst does not start from the share it had before a long idle.
    We will run the M4 Pro and A18 Pro side to confirm nothing changes there.

Two submitters that both saw the window end each swapped the busy total,
and the second reported about 0 permille for the same window, which on
T6041 also counted as a quiet window. Only the submitter that moves the
window start reports it now.

Forget the reported share when the GPU goes idle, so that a new burst
starts at the top of the ladder instead of from the share before a long
idle.

Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
@AxxzyWasTaken

Copy link
Copy Markdown
Contributor Author

Thanks. The race is fixed in 2a87da9: report_busy() now does a compare_exchange on BUSY_WINDOW_START, and only the submitter that wins it swaps the total and reports. I also took the optional part: apple_clpc_gpu_set_active(false) clears busy_valid, so a burst after idle starts at the top of the ladder.

Boot of this head on the M4 Max (J616c), release 7.3.0-j616c-pr1369, built with the daily kernel's config:

  • Boots. The CLPC status shows the T6041 table picked by machine compatible (dcs map 1,1,3,4, soc map 0,0,0,0). Light effort engages when the GPU is quiet (effort_full=false at idle).
  • GPU smoke. vulkan-msaa-mrt (2x, including a 6-target spilling layout), vulkan-msaa-xfer and aurora-tile-visit all PASS, plus 6 repeated tile-visit runs. No G17 errors or GPU recovery in the kernel log. aurora-r11g11b10f fails only with the Mesa build installed on the Max; with the test build it was written against, it passes on this kernel too. So it's userspace, not this PR.
  • Scrolling power: not done yet. The run was cut short when the Max was rebooted onto its daily kernel by other work. Note also that this head has no backlight device (the daily's display patches aren't in it), so its total power wouldn't be directly comparable to the earlier numbers anyway. I'll post the scrolling result from a boot that has the backlight.

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.

2 participants