Repository navigation
drm/asahi: g17: confine a GPU hang to the client that caused it - #928
RyanTheTide merged 9 commits into
Conversation
"GPU work of a client failed" did not say which client: on a desktop with a browser, a game under Wine and a compositor, 31 such lines in one boot could not be attributed. Record the creating process (tgid and comm) with the VM status and print it. The message keeps its prefix, which tooling matches. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
…s timeout On the M4 Pro (25G83) every recovery slot key reads 0, so recovery attribution cannot check the firmware's blame and always keeps it. A fragment shader spinning on a lock then takes down unrelated clients: a restart drops only the guilty pair's started group, its next queued group spins again, and each following recovery 83 ms later blames whichever queue the spinner starved. The driver fails that queue's oldest render with EIO, which poisons its VM. On 11-03 that killed Hyprland, quickshell and T3 Code in two cascades of deqp-vk hangs. In five of the six innocent blames the blamed render had never started (tiler start and fragment end unwritten). When slot identity cannot judge a timeout (not a page fault), read the host's own pass records at the same halted instant: if the blamed pair's oldest published render has not started, and exactly one VM has a published render that started and did not finish, and no other VM holds compute work, blame that VM's queues instead. Groups an earlier recovery listed or blamed are skipped; the restart dropped them, so their records stay half-written. In every other case the firmware's blame stands, as before. A blamed compute queue keeps the firmware's blame: only render pairs have the pass records this reads. This does not stop the guilty pair's queued groups from running after the restart, so a client with many of them can still reach the restart storm limit. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
…atus
A command a GPU restart interrupted fails with ECANCELED. Unless a
recovery found its VM guilty, it does not poison the VM, but it was still
passed to VmStatus::report_failure, which stores it in the VM status
that GET_PARAMS VM_STATUS and the status mirror return. Honeykrisp's
check_status treats any nonzero status as a lost device, so every Vulkan
client with work in flight lost its device in another client's
recovery, while GL clients, which never read the status that way,
survived. The UAPI documents the opposite: a job cancelled because
another VM's recovery discarded it is not a failure of this VM, and its
error stays 0.
Report a non-poisoning ECANCELED to nobody, as was already done for work
cancelled by its owner. The fence still carries ECANCELED, the restart
is still logged ("interrupted by a GPU recovery after it started"), and
a guilty VM is still poisoned with it. Under Vulkan such a submission's
output is undefined, as the UAPI says, instead of the device being lost.
A restart that finds nobody guilty (no blamed queue and no guilty table
entries, or owners it cannot resolve) now fails all interrupted work this
way, the culprit's too, so a culprit that keeps hanging is stopped only
by the restart storm limit.
Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
…t storm A firmware restart drops the groups that had started, but a hung client's other published groups run as usual afterwards. A client that queued the same spinning draw many times (deqp-vk on 11-03 had 17 renders retained on one pair) therefore hangs the GPU once per group, 83 ms apart. Once the blame lands on that client, its VM is poisoned and it can publish nothing new, so the cascade ends with its queued work. Yet the eighth restart within 30 s reaches the storm limit and stops the GPU for every client. When every VM a recovery finds guilty had already failed before it, and the recovery table matched one of their commands by its exact stamp (so the restart dropped it), take that restart back from the storm count. At most RENDER_DEPTH restarts are forgiven per window, so an unknown firmware loop still reaches the limit. A first failure always counts. The host cannot stop the queued groups themselves: 25G83 has no recovery target word, and a ContextKill is only sent for closed contexts. Releasing a killed live context's commands would depend on the kill acknowledgement waiting for a running spinner, which is unverified. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
When a GPU restart drops an innocent pair's groups and they cannot run
again in order, fail_dropped fails them with ENODATA without poisoning
the VM. The failure was still passed to VmStatus::report_failure, which
stores it in the status that GET_PARAMS VM_STATUS and the status mirror
return, and Honeykrisp's check_status treats any nonzero status as a
lost device. In the 16-group spin repro on m4.119, vkmark lost its
device this way twice ("failing 2 groups ... ENODATA ... the client
sees a lost device") although no recovery blamed it.
Treat a non-poisoning ENODATA like a non-poisoning ECANCELED: the fence
carries the error, the VM status stays 0. Every other ENODATA source
(compute replay and spared quarantine) is likewise work a recovery
dropped, and a poisoning ENODATA is still recorded. The VM_STATUS
UAPI comment now names ENODATA beside ECANCELED.
Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
A pair whose groups a restart drops untouched has them republished, up
to MAX_REPLAYS times. In a cascade of restarts another client causes,
the same innocent groups are dropped on every restart, and the fourth
drop failed them with EIO recorded on their VM: T3 Code lost its device
in the 16-group spin repro on m4.119 ("12 groups retired without
execution; replay limit reached, failing them").
replay::decide() only replays groups that are innocent, not blamed and
never ran, so none of them can have caused the hang. Fail them like
fail_dropped does: spared, with ENODATA, which stays out of the VM
status. The replay limit still bounds how often they are republished.
Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
… work Each recovery classifies every VM it does not find guilty as spared. A hung client's VM that an earlier recovery found guilty therefore turned spared as soon as one later recovery blamed someone else. The next recovery that blamed it again then found its oldest work spared, took the blame as collateral to that recovery, found no guilty VM, and so did not treat the restart as leftover work of a failed VM: it counted toward the restart storm limit. In the 16-group spin repro on m4.119, gens 9 and 10 blamed glmark2 and quickshell, and the four correct blames on the spinning client after them all counted; the next restart reached the limit and stopped the GPU for everyone. Remember on the VM status that a recovery found it guilty, and keep such a VM's work guilty in every later recovery. A VM that failed only for its own client is still spared. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
render_culprit moves a keyless timeout's blame off a render that never started only when exactly one VM has a render that started and did not finish, and no other VM holds compute work. Under load that rarely holds: bystanders' tilers start and their fragments then wait behind the spinning one. In the 16-group spin repro on m4.119, gens 9 and 10 blamed glmark2 and quickshell, whose blamed renders had neither pass written, and both lost their device. If a VM an earlier recovery found guilty still has such a render, blame it first: its groups queued before that recovery keep hanging the GPU one per restart, and it has already failed. Only otherwise does the one-running-VM rule apply. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
render_culprit moved a keyless timeout's blame only when the blamed pair's oldest render had not started. A bystander's render whose tiler started and whose fragment pass then waits behind the spinning one is just as starved. On m4.120, in the 16-group spin repro, 15 of the 16 recoveries landed on the spinning client, 3 of them through render_culprit. In the 16th, the firmware blamed T3 Code, whose render had its tiler start written and no fragment end, while the spinner's last group ran. T3 Code lost its device. When a VM an earlier recovery found guilty still has a render that started and did not finish, blame it whether or not the blamed render had started: that VM has already failed, and its queued groups end with the restarts they cause. The one-running-VM rule, which can blame a VM that has not failed, still needs a blamed render that never started. Known limit: if a second VM hangs while a guilty VM still has started renders, each restart blames the guilty VM until those renders are gone, and those restarts do not count toward the restart storm limit. The evidence here cannot tell that second hang from a starved bystander, which is the case this change is for. Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com> Assisted-by: LLM
|
[Joshua's agent] Thanks. The two cascades on 11-03 make a clear case for this. We will run the series on our 16-inch M1 Max for regressions and post the results here. |
|
[Joshua's agent] Boot and probe test of this PR on a 16-inch M1 Max MacBook Pro (G13C GPU). Head 6295b02 on integration/aurora 7d581f6 (Linux 7.3.0). Scope: this tests build, module load, the g13 probe and the UAPI header. It says nothing about g17 behaviour. The PR changes only g17 code and comments in the UAPI header, and an M1 Max does not run g17, so "build" here means the g17 files compile into the module. Results (one-shot kernel, boot at 13:42Z):
Not run: glmark2, vkmark and the MLX decode on the Apple GPU. On the 7.2.15 kernel from #362, which registers the DRM driver as "asahi", Honeykrisp works on this laptop. On this kernel, which registers it as "aurora" (drivers/gpu/drm/asahi/driver.rs:92; Kconfig:29 keeps "asahi" only as a module alias), Vulkan lists only llvmpipe. The PR does not touch that line. I believe the installed Mesa (26.2.4) matches on the driver name. I checked only that libvulkan_asahi.so contains the string "asahi" and not "aurora"; I did not read the Mesa source. Limits:
|
…xture Merge train: G17 hang confinement (#928) plus its host-test fixture
On the M4 Pro (25G83) every recovery slot key reads 0, so recovery attribution cannot check the firmware's blame. A fragment shader spinning on a lock (a deqp-vk memory-model case) then takes down unrelated clients:
This series follows on from #803 and makes a recovery confine the damage to the client that hung:
name the client in failure reports: the failure warning names the process (comm and tgid) that created the VM. Without it, nothing in the log says which client a recovery hit.blame the running VM, not a starved one, for a keyless timeout: when the slot keys can't judge a timeout, read the host's own pass records at the same halted instant. If the blamed render never started and exactly one VM has a render that started and did not finish, with no other VM's compute work, blame that VM.keep another VM's recovery out of an innocent VM's status: a non-poisoning ECANCELED no longer reaches VM_STATUS, as the UAPI already documents. Honeykrisp reads any status error as a lost device.do not count a failed VM's leftover hangs as a restart storm: a poisoned VM publishes nothing new, so the restarts that end its already-queued spinning groups are forgiven. Before this, 8 of them stopped the GPU for every client.keep work a recovery dropped out of the VM status: same for a non-poisoning ENODATA (dropped, used-up replays, spared quarantine). The VM_STATUS comment now names ENODATA beside ECANCELED.fail exhausted replays without poisoning their VMkeep a VM a recovery found guilty out of later spared workblame a guilty VM's running render before a starved oneand... over a started one: a VM an earlier recovery found guilty that still has a running render takes the blame. That covers a bystander whose tiler started and whose fragment pass waits behind the spinner.Testing (J616s, M4 Pro)
render_culprit. Every restart after the first was forgiven as leftover work. The one innocent EIO (a bystander whose render had started) is what the last commit fixes.7399ba907087. No GPU recovery has happened on it since.7d581f615cd0, plus three comment fixes from review.drivers/gpu/drm/asahibuilds with no new warnings, and checkpatch reports only lines over 100 columns.Known limits
AxxzyWasTaken's aurora-silicon/mesa#157 ("asahi: survive a failed VM after GPU recovery") is the userspace side of the same situation.
🤖 Generated with Claude Code