Skip to content

drm/asahi: skip G17 event-pass housekeeping for completion records alone - #494

Merged
DjDeveloperr merged 1 commit into
integration/aurorafrom
perf/g17-event-worker-20261026
Oct 27, 2026
Merged

DjDeveloperr merged 1 commit into
integration/aurorafrom
perf/g17-event-worker-20261026

Conversation

@DjDeveloperr

Copy link
Copy Markdown
Contributor

Stacked on #468 (the base is its branch, so only this commit shows). It retargets to integration/aurora when #468 merges.

Summary

Every completion notification queues a G17 event pass. Every pass ran the full housekeeping after retiring its records:

  • render linger expiry;
  • drained-pair reclaim;
  • compute exit settlement;
  • compute pool recycling and vacating;
  • evicted render pool vacating;
  • heap shrinking and teardown.

Each of these scans every compute queue, render entry or pool. Light rows run about 40,000 passes a second, so the scans took a large part of the event worker's time on the IRQ CPU, and with AIC2 routing that is always CPU 0. Retiring a completion and signalling its fence needs none of them.

The housekeeping now runs only when one of these holds:

  • the pass was requested through queue_events();
  • recovery is in progress;
  • a teardown is pending;
  • something is waiting for channels, progress, queue slots or render capacity;
  • no work remains in flight;
  • the bounded fallback: the first pass 1 ms after the last full one.

Three paths queue a pass for the records alone: the firmware's event notification, records that arrive during a pass, and render events missed while a pair was on loan. Every other caller still gets a full pass. Retirement, fence signalling, replay, render observation, the polling scan and render-waiter notification still run on every pass, and so do the firmware trace and statistics ring drains.

I also tried moving the event work off the IRQ CPU: an unbound high-priority workqueue, the submitter's CPU, or the other P-core. Every option was slower, by up to +86% on compute d2 and the hop rows, because of the cross-CPU wakeup and the slower E-cores. So the work stays where it is, and this cuts its cost instead.

Measurements

Neo, same boot, against every pass running the housekeeping. Alternating, four rounds, medians:

before after
event pass (sync.signal + render.light procs) 8.2 µs 6.2 µs
event worker share of CPU 0, all rows 24.9% 20.8%
compute.light procs d2 36.80 µs 34.81 µs (better in 4/4 rounds)
compute.light queues d2 36.76 µs 34.96 µs (better in 4/4 rounds)
submit.empty queue d2 1.78 µs 1.69 µs

compute.light queue d1/d2/d64 and queues d4, render.light d1/d32 and queues d4/d8, render.light procs d2, sync.signal binary/timeline, concurrent.cr and the cross-queue pair all stay within 2%.

Testing

  • Regression gate: PASS (cross-queue pair 225.4 µs, order 131.1 µs, vkstress bad=0, pressure pass, no new faults).
  • Targeted CTS: 4687 Pass / 681 NotSupported / 0 Fail.
  • drm/asahi: improve G17 submission, queue admission and completion #423's five-lane multi-client stress, 10 minutes each against the merged driver (global-priority CTS, process churn, render fill, a second render lane, 1.5 s compute dispatches): 0 job timeouts, restarts, ENODATA or faults in both; 42 global-priority CTS iterations all pass; 0 of 319 long dispatches lost.
  • CTS: api.object_management, synchronization and synchronization2, 146,944 cases with 0 Fail / 0 Crash. The per-group counts match the merged driver's broad run exactly.

Exit settlement and pool recycling under live traffic can now wait up to 1 ms. Recovery and pending teardowns always get full passes.

Every completion notification queues an event pass, and every pass ran
the full housekeeping after retiring the records: render linger expiry,
drained-pair reclaim, compute exit settlement, compute pool recycling and
vacating, evicted render pool vacating, heap shrinking and teardown. Each
of these scans every compute queue, render entry or pool, so with around
40000 passes a second in light rows the scans took a large part of the
event worker's time on the IRQ CPU, while retiring a completion and
signalling its fence needs none of them.

Run that housekeeping only when a pass is requested through
queue_events(), on recovery, while a teardown is pending, while anything
waits for channels, progress, queue slots or render capacity, when no work
remains in flight, and at the latest on the first pass 1 ms after the last
full one. The firmware's event notification, records that arrive during a
pass and render events missed while a pair was on loan queue a pass for
the records alone. Every other caller keeps getting a full pass.

Measured on Neo in the same boot against every pass running the
housekeeping, alternating, four rounds (medians):

  event pass, sync.signal + render.light procs   8.2 -> 6.2 us
  event worker share of CPU0, all rows           24.9% -> 20.8%
  compute.light procs d2                         36.80 -> 34.81 us
  compute.light queues d2                        36.76 -> 34.96 us
  submit.empty queue d2                          1.78 -> 1.69 us

compute.light queue d1/d2/d64, queues d4, render.light d1/d32 and queues
d4/d8, render.light procs d2, sync.signal binary/timeline, concurrent.cr
and the cross-queue pair stay within 2%.
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