You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
agc: Driver::stop waits for every queued library prebuild, so the first session on a new build takes minutes to exit #8470
Driver::stop calls CloseRegistrationPreparation() (Lifecycle.cpp:166) before device.Reset() (line 170), where the teardown pipeline-cache save runs (PipelineCache.cpp:86). RegistrationPreparePool::Close() waits until its queue is empty (ShaderRegistry.cpp:1205), and the prebuild pool has one thread unless APS5_PREBUILD_THREADS is set (line 1118). After a shader recompiler change, when many libraries are not in the driver's cache yet, every queued prebuild is built before the process can exit.
Measured on GTA V (PPSA04263 01.010.002), Performance mode, the time from SIGINT (SDL turns it into the normal quit path) to process exit:
Linux, RTX 5060 Laptop GPU, NVIDIA 615.71.09: 554 s on main eaa5c92 and 455 s on main d14a186, each the first run of that build.
Linux, RTX 4060, NVIDIA 580.126.20: 573 s on main eaa5c92, first run of that build.
The same builds on later runs, with warm caches: 1 to 3 s.
Each run did write the teardown save once the queue was empty. A player or script that ends the process before that loses every pipeline built in the session, so the next start is cold again.
Prebuilds only build libraries ahead of first use with a placeholder state, so skipping the queued ones at shutdown loses nothing a later run needs. I'd like to open a PR that drops the queued (not the running) prebuild tasks when the pool closes at shutdown, with a test that queues several and checks that close returns after the running one and that the queued ones never run. The shader-preparation pool and AwaitLibraryPrebuilds in device replacement would stay as they are.
@adriadam10, since this is the prebuild from #4152: is dropping queued prebuilds at shutdown acceptable, or would you rather they stay and the teardown save move ahead of the close?
I traced the current pool lifecycle. CloseRegistrationPreparation() calls CloseAll(), which closes both the registration-preparation pool and the separate library-prebuild pool. AwaitLibraryPrebuilds() is also used during Vulkan device replacement, so any queue cancellation should be limited to shutdown and the prebuild pool; the device-replacement wait should keep draining normally.
For shutdown, finishing the currently running prebuild, dropping only not-yet-started speculative prebuilds, and then continuing to device.Reset()/the pipeline-cache save seems consistent with the behavior described here. One detail for the implementation: discarded tasks need their unfinished tickets removed and idle waiters notified, or a concurrent AwaitSubmitted() could wait forever. The existing ShutdownThreads test already exercises pool shutdown; it could cover a blocked running task, queued tasks that must not run, and waiter wakeup.
Thanks @MarcZX10, that matches what I measured. The PR is up as #8678: the prebuild pool drops its not-started tasks at close, erases their tickets from unfinished and notifies idle, and waits for the running one; the preparation pool and the device-replacement wait are unchanged. The new ShutdownThreads case covers a blocked running prebuild and queued ones that must not run. I'll add the concurrent AwaitSubmitted waiter you mention to that test.
GTA V, cold library caches, SIGINT to exit: 432 and 630 s on main against 2 s with the change (RTX 5060 Laptop, 615.71.09), and 859 and 865 s against 2 s (RTX 4060, 580.126.20).
Activity
MarcZX10 commentedon Oct 20, 2026
I traced the current pool lifecycle.
CloseRegistrationPreparation()callsCloseAll(), which closes both the registration-preparation pool and the separate library-prebuild pool.AwaitLibraryPrebuilds()is also used during Vulkan device replacement, so any queue cancellation should be limited to shutdown and the prebuild pool; the device-replacement wait should keep draining normally.For shutdown, finishing the currently running prebuild, dropping only not-yet-started speculative prebuilds, and then continuing to
device.Reset()/the pipeline-cache save seems consistent with the behavior described here. One detail for the implementation: discarded tasks need theirunfinishedtickets removed andidlewaiters notified, or a concurrentAwaitSubmitted()could wait forever. The existingShutdownThreadstest already exercises pool shutdown; it could cover a blocked running task, queued tasks that must not run, and waiter wakeup.CPritch commentedon Oct 20, 2026
Thanks @MarcZX10, that matches what I measured. The PR is up as #8678: the prebuild pool drops its not-started tasks at close, erases their tickets from
unfinishedand notifiesidle, and waits for the running one; the preparation pool and the device-replacement wait are unchanged. The newShutdownThreadscase covers a blocked running prebuild and queued ones that must not run. I'll add the concurrentAwaitSubmittedwaiter you mention to that test.GTA V, cold library caches, SIGINT to exit: 432 and 630 s on main against 2 s with the change (RTX 5060 Laptop, 615.71.09), and 859 and 865 s against 2 s (RTX 4060, 580.126.20).
AI-assisted: yes