WIP: perf(vk): new pipelines are in the game's own cache before their first draw, which asks it instead of being left out #40

Closed
HumanBean wants to merge 9 commits from HumanBean/Longshot:perf/first-draw-asks-caches into main
Owner

Status: not ready to merge. The first-draw ask and the warm's cost are measured in a game; the cap on the warm, the hit rate of what it keeps and the budget for long frames have not run in a game (see "Not tested yet").

What

Two parts:

  1. The game's first start after a preparation also builds predicted pipelines (those of program variants no list names) into its own pipeline cache and lets each go, after the noted and compute ones. It is bounded twice: it stops once it has added 200 MB to the cache (RX_VK_WARM_PREDICTED_MB; 0: none, the pass is not made) or after 60 s (RX_VK_WARM_PREDICTED_S). The pipelines of programs a list names in another variant go first. What it does not reach is asked for at first draw and built by the workers where no cache has it, as on main. RX_VK_WARM_PREDICTED=0: off. It is skipped where the same process prepared the shaders.
    It runs only where programs are loaded at create calls (GPUs with native mesh shaders, no longshot_load_start.txt, no compressed program cache, or RX_VK_LOAD=create), in a play process's first start on a folder without the "built" marker. Where programs are loaded before the title (start mode) the start keeps every listed pipeline ready as before and this pass does not exist.
  2. A draw whose pipeline is new asks the caches itself, without compiling, before the draw is left out: this process's own cache first, then the driver's. Only a pipeline that needs compiling, or is past the frame's budget, goes to a worker and has its draw left out, as before. The budget is 3 ms a frame, or a quarter of the frame's length where the frame is already long (an area loading), 60 ms at most; one ask is always allowed. A frame's asks stop after three in a row that no cache answers (a cold driver cache), so such a frame costs three asks and not its whole budget; an answer begins the count again. RX_VK_FIRST_ASK=0: off.

Why the game's own cache

What an ask for a predicted pipeline costs in a later session (RTX 3090, Linux; 32 sampled predicted pipelines asked at start-up, the ask alone timed; all 32 answered each time):

asked of mean median worst
the game's own cache file 0.37 ms 0.37 ms 0.87 ms
the same again 0.29 ms 0.30 ms 0.58 ms
an empty cache, so the driver's disk cache 3.48 ms 3.50 ms 8.78 ms
a second empty cache in the same process, so the driver's memory 2.13 ms 2.11 ms 4.15 ms

Only the game's own cache answers in well under a millisecond. On NVIDIA the cache file a --prepare-shaders process writes does not answer the game's process, so the game has to build them itself once.

What it costs, and why the cap

A folder prepared by --prepare-shaders (the Builder's way), then the game; RTX 3090, Linux, loads at create calls, a short tour of three areas. These runs put all 50,547 predicted pipelines into the cache (the commit before the cap):

first start, all predicted in second start first start, RX_VK_WARM_PREDICTED=0
shaders at start-up 37.1 s 2.1 s 8.0 s
the predicted pass 20.6 s: 50,547 answered by the driver's cache, 0 compiled none off
pipeline cache file 2.03 GB 2.03 GB 1.30 GB
heap in use in the first area 4,378 MB 4,214 MB 3,568 MB
process resident in the first area 12,255 MB 11,996 MB 11,445 MB
draws left out 0 0 0
pipeline work a frame, 99th percentile / worst 0.46 / 1.9 ms 0.43 / 5.8 ms 0.45 / 4.8 ms
  • One run of each. A second first start took 14.8 s for the pass and 26.3 s at start-up.
  • With all of them in, the file is 0.73 GB bigger and every later session holds about 650 MB more: the file is read whole at each start and the driver keeps it for the session, about 0.9 MB of memory for each MB of file, 14.6 KB a predicted pipeline. That is why the pass is capped at 200 MB, about 14,000 pipelines on this driver.
  • This tour draws no new pipelines, so it shows the cost and not the benefit; the benefit is in the session below.
  • The same pass compiled cold takes 218 s on this PC and 1,132 s on an RX 580 (inside a preparation), which is why it also has a time bound.

Start mode: only the ask changes

RX 580 (RADV, no mesh shaders, so start mode by default), 16 GB, a cold --prepare-shaders (2,040 s), then the game's first start twice from that same prepared state:

first start, default first start, RX_VK_WARM_PREDICTED_MB=0
in play after 179 s 155 s
predicted pass did not run (start mode) did not run
pipeline cache file 343 MB, unchanged 343 MB, unchanged
first-draw asks 9 asked, 0 answered, 2.3 ms in all, slowest 1.0 ms 4 asked, 0 answered, 2.0 ms in all
pipelines compiled in play 9 4
draws and dispatches left out 28 10
peak memory (limit 12 GB + 4 GB swap) 16.4 GB 16.1 GB
  • Neither start ran the pass, so the 24 s between them is spread (the start's own load took 103 s against 90 s).
  • The asks found nothing in a cache: a "no" cost about 0.25 to 0.5 ms, and the pipeline then went to a worker as before.
  • Both starts were at the memory limit; that is start mode on this PC with or without this change.

Game tests of the ask

A new game's opening on a freshly prepared folder, RTX 3090, Linux, prepared inside the game's own start:

first-draw ask only with the own-cache ask (commit 6a18ec05)
new pipelines asked by their first draw 423 1,388
answered by the driver's disk cache: 423 the first cache asked, in memory: 1,388
cost of an ask 2.8 ms 0.27 ms (slowest 6.2 ms)
past the frame's budget (the old path) 1,650 1,787
frames with draws left out 113 42
draws and dispatches left out 5,675 5,909
pipelines compiled in play 0 0
frames with over 3 ms / over 8 ms of pipeline work 199 / 31 50 / 9

The two sessions are not the same route or length, so the counts are not a strict before/after.

  • An answer from the driver's disk cache costs about 3 ms, so a 3 ms budget carried about one ask a frame; from the game's own cache it is 0.27 ms.
  • In the second session the pipelines asked were ones that process's own preparation had built into its cache. At that commit the predicted pass itself still built for the driver only; a later commit on the branch makes it build into the game's cache.
  • What was left in that session: five bursts at scene loads (550 to 2,300 draws left out over 1 to 12 frames, in frames already 120 to 370 ms long) and about 15 ordinary frames that left 1 to 21 draws out when the 3 ms was used up by about 12 asks. The budget for long frames is the answer to both; it is not confirmed in a game.

Not tested yet

  • The capped pass has not run on any GPU; only the uncapped one has (20.6 s and 14.8 s on an RTX 3090). So, in a game: how much the cap really adds, the pass's time with it, the overshoot past 200 MB (the cache's size is asked of the driver about once a second), and what that size query costs.
  • Whether the order picks the right pipelines: how many of a new game's first draws the capped cache answers. The log's warm line says how many predicted pipelines are of programs a list names in another variant, and the first draws: line splits the answers by own cache and driver.
  • The budget rule for long frames. From the session above it should serve each scene-load burst in its first one or two frames (an estimate from the frame trace). The price: a load frame that is already long can be up to 60 ms longer.
  • The time bound cutting the pass: it never came near 60 s on the RTX 3090, and the pass does not run on the RX 580 in its default mode. No slow GPU has run it.
  • The stop after three misses in a row: unit tested only. A "no" was measured only as 0.25 to 0.5 ms each on RADV, for 9 pipelines; a cold driver cache with hundreds of new pipelines has not run. The first draws: line counts the frames stopped that way.
  • Memory with the bigger cache where programs are loaded before the title (start mode): no comparison run.
  • A cold driver cache; AMD, Intel, Windows.
  • The full test suite on the last commits.

Tests

  • tests/test_first_ask.py: the budget rule compiled and run alone; source checks that the ask is without compiling, inside the budget and before the worker hand-off.
  • tests/test_warm_bounded.py: the time bound and the cap as rules; source checks that the pass builds into the game's cache, is bounded both ways, and that the marker is still written after the cache is saved.
  • test_program_load_wait, test_program_life and the predict tests pass. The renderer builds on Linux.
  • The branch has main merged in (the rename to Longshot). The game runs above were made before that merge; after it only the renderer build and these tests were run.
**Status: not ready to merge. The first-draw ask and the warm's cost are measured in a game; the cap on the warm, the hit rate of what it keeps and the budget for long frames have not run in a game (see "Not tested yet").** ## What Two parts: 1. The game's first start after a preparation also builds predicted pipelines (those of program variants no list names) into its own pipeline cache and lets each go, after the noted and compute ones. It is bounded twice: it stops once it has added 200 MB to the cache (`RX_VK_WARM_PREDICTED_MB`; `0`: none, the pass is not made) or after 60 s (`RX_VK_WARM_PREDICTED_S`). The pipelines of programs a list names in another variant go first. What it does not reach is asked for at first draw and built by the workers where no cache has it, as on main. `RX_VK_WARM_PREDICTED=0`: off. It is skipped where the same process prepared the shaders. It runs only where programs are loaded at create calls (GPUs with native mesh shaders, no `longshot_load_start.txt`, no compressed program cache, or `RX_VK_LOAD=create`), in a play process's first start on a folder without the "built" marker. Where programs are loaded before the title (start mode) the start keeps every listed pipeline ready as before and this pass does not exist. 2. A draw whose pipeline is new asks the caches itself, without compiling, before the draw is left out: this process's own cache first, then the driver's. Only a pipeline that needs compiling, or is past the frame's budget, goes to a worker and has its draw left out, as before. The budget is 3 ms a frame, or a quarter of the frame's length where the frame is already long (an area loading), 60 ms at most; one ask is always allowed. A frame's asks stop after three in a row that no cache answers (a cold driver cache), so such a frame costs three asks and not its whole budget; an answer begins the count again. `RX_VK_FIRST_ASK=0`: off. ## Why the game's own cache What an ask for a predicted pipeline costs in a later session (RTX 3090, Linux; 32 sampled predicted pipelines asked at start-up, the ask alone timed; all 32 answered each time): | asked of | mean | median | worst | |---|---|---|---| | the game's own cache file | 0.37 ms | 0.37 ms | 0.87 ms | | the same again | 0.29 ms | 0.30 ms | 0.58 ms | | an empty cache, so the driver's disk cache | 3.48 ms | 3.50 ms | 8.78 ms | | a second empty cache in the same process, so the driver's memory | 2.13 ms | 2.11 ms | 4.15 ms | Only the game's own cache answers in well under a millisecond. On NVIDIA the cache file a `--prepare-shaders` process writes does not answer the game's process, so the game has to build them itself once. ## What it costs, and why the cap A folder prepared by `--prepare-shaders` (the Builder's way), then the game; RTX 3090, Linux, loads at create calls, a short tour of three areas. These runs put **all** 50,547 predicted pipelines into the cache (the commit before the cap): | | first start, all predicted in | second start | first start, `RX_VK_WARM_PREDICTED=0` | |---|---|---|---| | shaders at start-up | 37.1 s | 2.1 s | 8.0 s | | the predicted pass | 20.6 s: 50,547 answered by the driver's cache, 0 compiled | none | off | | pipeline cache file | 2.03 GB | 2.03 GB | 1.30 GB | | heap in use in the first area | 4,378 MB | 4,214 MB | 3,568 MB | | process resident in the first area | 12,255 MB | 11,996 MB | 11,445 MB | | draws left out | 0 | 0 | 0 | | pipeline work a frame, 99th percentile / worst | 0.46 / 1.9 ms | 0.43 / 5.8 ms | 0.45 / 4.8 ms | - One run of each. A second first start took 14.8 s for the pass and 26.3 s at start-up. - With all of them in, the file is 0.73 GB bigger and every later session holds about 650 MB more: the file is read whole at each start and the driver keeps it for the session, about 0.9 MB of memory for each MB of file, 14.6 KB a predicted pipeline. That is why the pass is capped at 200 MB, about 14,000 pipelines on this driver. - This tour draws no new pipelines, so it shows the cost and not the benefit; the benefit is in the session below. - The same pass compiled cold takes 218 s on this PC and 1,132 s on an RX 580 (inside a preparation), which is why it also has a time bound. ## Start mode: only the ask changes RX 580 (RADV, no mesh shaders, so start mode by default), 16 GB, a cold `--prepare-shaders` (2,040 s), then the game's first start twice from that same prepared state: | | first start, default | first start, `RX_VK_WARM_PREDICTED_MB=0` | |---|---|---| | in play after | 179 s | 155 s | | predicted pass | did not run (start mode) | did not run | | pipeline cache file | 343 MB, unchanged | 343 MB, unchanged | | first-draw asks | 9 asked, 0 answered, 2.3 ms in all, slowest 1.0 ms | 4 asked, 0 answered, 2.0 ms in all | | pipelines compiled in play | 9 | 4 | | draws and dispatches left out | 28 | 10 | | peak memory (limit 12 GB + 4 GB swap) | 16.4 GB | 16.1 GB | - Neither start ran the pass, so the 24 s between them is spread (the start's own load took 103 s against 90 s). - The asks found nothing in a cache: a "no" cost about 0.25 to 0.5 ms, and the pipeline then went to a worker as before. - Both starts were at the memory limit; that is start mode on this PC with or without this change. ## Game tests of the ask A new game's opening on a freshly prepared folder, RTX 3090, Linux, prepared inside the game's own start: | | first-draw ask only | with the own-cache ask (commit 6a18ec05) | |---|---|---| | new pipelines asked by their first draw | 423 | 1,388 | | answered by | the driver's disk cache: 423 | the first cache asked, in memory: 1,388 | | cost of an ask | 2.8 ms | 0.27 ms (slowest 6.2 ms) | | past the frame's budget (the old path) | 1,650 | 1,787 | | frames with draws left out | 113 | 42 | | draws and dispatches left out | 5,675 | 5,909 | | pipelines compiled in play | 0 | 0 | | frames with over 3 ms / over 8 ms of pipeline work | 199 / 31 | 50 / 9 | The two sessions are not the same route or length, so the counts are not a strict before/after. - An answer from the driver's disk cache costs about 3 ms, so a 3 ms budget carried about one ask a frame; from the game's own cache it is 0.27 ms. - In the second session the pipelines asked were ones that process's own preparation had built into its cache. At that commit the predicted pass itself still built for the driver only; a later commit on the branch makes it build into the game's cache. - What was left in that session: five bursts at scene loads (550 to 2,300 draws left out over 1 to 12 frames, in frames already 120 to 370 ms long) and about 15 ordinary frames that left 1 to 21 draws out when the 3 ms was used up by about 12 asks. The budget for long frames is the answer to both; it is not confirmed in a game. ## Not tested yet - The **capped** pass has not run on any GPU; only the uncapped one has (20.6 s and 14.8 s on an RTX 3090). So, in a game: how much the cap really adds, the pass's time with it, the overshoot past 200 MB (the cache's size is asked of the driver about once a second), and what that size query costs. - Whether the order picks the right pipelines: how many of a new game's first draws the capped cache answers. The log's warm line says how many predicted pipelines are of programs a list names in another variant, and the `first draws:` line splits the answers by own cache and driver. - The budget rule for long frames. From the session above it should serve each scene-load burst in its first one or two frames (an estimate from the frame trace). The price: a load frame that is already long can be up to 60 ms longer. - The time bound cutting the pass: it never came near 60 s on the RTX 3090, and the pass does not run on the RX 580 in its default mode. No slow GPU has run it. - The stop after three misses in a row: unit tested only. A "no" was measured only as 0.25 to 0.5 ms each on RADV, for 9 pipelines; a cold driver cache with hundreds of new pipelines has not run. The `first draws:` line counts the frames stopped that way. - Memory with the bigger cache where programs are loaded before the title (start mode): no comparison run. - A cold driver cache; AMD, Intel, Windows. - The full test suite on the last commits. ## Tests - `tests/test_first_ask.py`: the budget rule compiled and run alone; source checks that the ask is without compiling, inside the budget and before the worker hand-off. - `tests/test_warm_bounded.py`: the time bound and the cap as rules; source checks that the pass builds into the game's cache, is bounded both ways, and that the marker is still written after the cache is saved. - `test_program_load_wait`, `test_program_life` and the predict tests pass. The renderer builds on Linux. - The branch has main merged in (the rename to Longshot). The game runs above were made before that merge; after it only the renderer build and these tests were run.
A draw whose pipeline no list named was left out until a worker had made the pipeline,
even where the driver's cache had it and answered in a fraction of a millisecond. A
new game's opening on a prepared folder drew 834 such pipelines, all from the driver's
cache and none compiled, and still left 1,906 draws and dispatches out (30 of 98
five-second windows, up to 11.4 a frame) with 290 waits.

The draw now asks the caches itself, without compiling (the build's existing
fail-on-compile-required ask), and goes on with the pipeline when they answer. Only one
that needs compiling goes to the worker and is left out, as before. The asks have a
budget a frame on each recording thread (first_ask.h: 24 asks, 3 ms; an ask is about
0.2 ms, 99 in 100 under 5 ms on an RTX 3090), past which the old path is taken, so a
burst of new states is served over a few frames. Both load modes take this path.
RX_VK_FIRST_ASK=0: off. The log's "first draws:" lines count asked, answered and past
the budget.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Co-Authored-By: Claude Fable 5.2 <[email protected]>
A new game's opening on a freshly prepared folder asked the caches for 423 new pipelines
at their first draws. All were answered, by the driver's disk cache, at 2.8 ms each: one
fits the frame's 3 ms budget, four in five took the old path, and the session still had
5,675 draws left out. These are the predicted pipelines, of program variants no list
names: the preparation builds them and lets them go, and on NVIDIA only the driver's disk
cache carries its work to the game's process.

- The first start of the game after a preparation (precompile_warm) now builds the
  predicted pipelines again, in its own process and into the cache it loads from then on,
  after the noted and compute ones. Not where this process has built them already (a
  preparation done inside the game's start), and never in a --prepare-shaders process.
  It logs how many the caches answered without compiling, how many were compiled, and
  the time. RX_VK_WARM_PREDICTED=0: off.
- The first draw's ask goes to this process's own cache first, then the driver's, as the
  loads at create calls and the stage libraries ask (an in-memory answer was measured at
  0.4 ms against 2.2 ms from the driver's disk cache for stage libraries).
- The "first draws:" line says how many asks each cache answered, with the time of each
  kind, how many were in no cache, and the slowest ask.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
With the asks answered by this process's own cache at 0.27 ms each, what stopped them
was the budget: 24 asks or 3 ms a frame. A new game's opening still left 5,909 draws out
in 42 frames. Five bursts where an area loads, in frames already 122 to 376 ms long, had
several hundred new pipelines in one frame and a budget for about a dozen. Fifteen
ordinary frames of 20 to 35 ms spent 3.4 to 4.3 ms on pipelines, which is the 3 ms of
asks at about 12 of them, and left 1 to 21 draws out for want of a few asks more.

The budget is now time alone: 3 ms in a short frame, a quarter of the frame's length
where the frame is longer (the longer of the frame before and of the time this one has
taken so far stands for it), 60 ms at most, and one ask is always allowed in a frame
that has asked nothing. A 25 ms frame begins 24 asks where 12 began, a 187 ms frame 174.
The worst a frame's asks add is its limit and one ask (the slowest of 1,388 was 6.2 ms).

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Two things about the pass over the predicted pipelines that the game's first start makes after a preparation.

It did not build into the game's pipeline cache. predict_run's workers hand the driver no cache of ours (its pipelines were
meant for the driver's own cache alone), and the pass added in 6a18ec05 went through them unchanged. The session that made
the pass had the pipelines in the driver's memory, which is what its fast first-draw answers were; a later start would have
had them from the driver's disk cache again. In that pass the workers now build into our cache, which is saved before the
marker is written.

It had no bound. Where the driver's cache does not answer, the pass is the compile of every predicted pipeline over again,
in front of the game: 220 s on an RTX 3090 and 19 minutes on an RX 580 from empty caches. It now stops after 60 s
(RX_VK_WARM_PREDICTED_S, 0 for no bound). The start goes on, the marker is written as before and the pass is not repeated;
what it did not reach is asked for at its first draw and built by the workers where no cache has it, as on main. The log
line says how many it reached and whether the bound cut it. The programs go in one order every time, those a note names in
another variant first: a guess at which are likelier to be drawn, not a measured one.

Not run in a game yet.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Built into the game's own cache, all 50,547 predicted pipelines made the file 0.73 GB bigger on an RTX 3090 (1.30 to
2.03 GB), and a later session held about 650 MB more for it: the file is read whole at every start and the driver keeps
it for the session, about 0.9 MB of memory for each MB of file, 14.6 KB a pipeline. What it buys is the answer at a first
draw: 0.37 ms from our cache where the driver's own takes 3.5 ms from disk and 2.1 ms from its memory (32 sampled
pipelines, a later session).

The pass now stops once it has added 200 MB (RX_VK_WARM_PREDICTED_MB; 0: none, the pass is not made), about 14,000
pipelines there, so its time shrinks with it. The cache's size is asked of the driver about once a second while the
workers build. The order is the one the pass already has: the pipelines of programs a list names in another variant
first. Whether those are the ones a new game draws is not measured; the log line now says how many of the predicted
pipelines are of such programs, how many went in, the MB added and whether the cap or the time bound stopped it, and
the first draws line's split (own cache, driver) shows what the cap left out.

Not run in a game.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Conflicts in docs/development.md, gpu/vk/vk_draw.cpp, gpu/vk/vk_draw.h and tests/test_warm_bounded.py: this branch's
side with the rename as main made it on the same lines (LONGSHOT_PREPARE_ONLY, the (longshot) comment mark). Two
comment marks in lines this branch added (first_ask.h, vk_draw.cpp) renamed the same way.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
An ask no cache answers is lost time: the pipeline goes to a worker all the same, later by the ask. On an RX 580 nine
of nine first-draw asks were in no cache, 0.25 to 0.5 ms each. With a cold driver cache an area's load could spend a
long frame's whole share, up to 60 ms, on asks that all say no, before its later pipelines reach the workers.

A frame's asks, on each recording thread, now stop after three misses in a row; an answer begins the count again, and
one ask is still always allowed in a frame that has asked nothing. A cold cache costs a frame three asks. The first
draws line counts the frames stopped that way.

Not run in a game.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
One conflict, docs/development.md: the guard's sentence in the RX_VK_FIRST_ASK row, the rows beside it as main renamed them.

Co-Authored-By: Claude Fable 5.2 <[email protected]>
Author
Owner

On hold, and its numbers should not be read as they stand.

Two more game tests on a folder prepared the Builder's way (a separate --prepare-shaders run, then the game) show that this pull request's code had nothing to do: a new game's opening and play, 22,288 frames, had 0 first-draw asks, 0 draws left out and 0 pipelines compiled; another session of 22,444 frames had 1 ask. In both, 7,519 and 10,260 graphics pipelines were made ready when the game created their programs.

The two sessions in the description's "Game tests" table (113 and 42 frames with draws left out) were on folders that the game prepared inside its own start. In such a start the programs the state list reads lose their records, the index of kept program keys has 32,719 keys instead of 47,866, and about 5,300 create calls for listed programs get nothing made ready ("8192 create calls with nothing kept for their stages" against 2,743). Their pipelines are then fetched at first draw and the draws are left out meanwhile. So that table measured a defect of the preparing start with listed pipelines, not pipelines no list names.

Next: confirm that with one controlled pair, fix the preparing start on its own branch, then see what is left for the first-draw ask. The capped warm did run here for the first time: 4.7 s, 16,404 of 50,954 predicted pipelines kept, 253 MB added; no session so far shows a benefit from it.

On hold, and its numbers should not be read as they stand. Two more game tests on a folder prepared the Builder's way (a separate `--prepare-shaders` run, then the game) show that this pull request's code had nothing to do: a new game's opening and play, 22,288 frames, had 0 first-draw asks, 0 draws left out and 0 pipelines compiled; another session of 22,444 frames had 1 ask. In both, 7,519 and 10,260 graphics pipelines were made ready when the game created their programs. The two sessions in the description's "Game tests" table (113 and 42 frames with draws left out) were on folders that the game prepared inside its own start. In such a start the programs the state list reads lose their records, the index of kept program keys has 32,719 keys instead of 47,866, and about 5,300 create calls for listed programs get nothing made ready ("8192 create calls with nothing kept for their stages" against 2,743). Their pipelines are then fetched at first draw and the draws are left out meanwhile. So that table measured a defect of the preparing start with listed pipelines, not pipelines no list names. Next: confirm that with one controlled pair, fix the preparing start on its own branch, then see what is left for the first-draw ask. The capped warm did run here for the first time: 4.7 s, 16,404 of 50,954 predicted pipelines kept, 253 MB added; no session so far shows a benefit from it.
Author
Owner

Closing. A controlled pair confirms what the comment above says: the same build, folder and tour, in create mode, prepared two ways.

prepared by --prepare-shaders prepared inside the game's start
kept program keys in the create-time index 47,866 32,719
graphics pipelines made at create calls 8,017 720
create calls with nothing kept for their stages 2,807 6,685
new graphics pipelines in play 0 1,587
draws and dispatches left out 0 5,594
pipeline waits 0 258 (573.5 ms)
pipelines compiled in play 0 0
heap in use in the first area 3,579 MB 5,397 MB

So the pop-in belongs to the start that prepares in its own process, with listed pipelines that no create call asked for, and a folder prepared the Builder's way has nothing for this pull request to act on. The fix for the preparing start is a separate, smaller change: let the programs the state list read go and give their records back before the create-time index is built (not written yet).

What was measured here and may be useful later: a pipeline asked at first draw costs about 0.3 to 0.4 ms from the game's own cache, 3.5 ms from NVIDIA's disk cache and 2.1 ms from the driver's memory; keeping all 50,547 predicted pipelines in the game's cache costs about 650 MB a session (about 14.6 KB each).

Closing. A controlled pair confirms what the comment above says: the same build, folder and tour, in create mode, prepared two ways. | | prepared by `--prepare-shaders` | prepared inside the game's start | |---|---|---| | kept program keys in the create-time index | 47,866 | 32,719 | | graphics pipelines made at create calls | 8,017 | 720 | | create calls with nothing kept for their stages | 2,807 | 6,685 | | new graphics pipelines in play | 0 | 1,587 | | draws and dispatches left out | 0 | 5,594 | | pipeline waits | 0 | 258 (573.5 ms) | | pipelines compiled in play | 0 | 0 | | heap in use in the first area | 3,579 MB | 5,397 MB | So the pop-in belongs to the start that prepares in its own process, with listed pipelines that no create call asked for, and a folder prepared the Builder's way has nothing for this pull request to act on. The fix for the preparing start is a separate, smaller change: let the programs the state list read go and give their records back before the create-time index is built (not written yet). What was measured here and may be useful later: a pipeline asked at first draw costs about 0.3 to 0.4 ms from the game's own cache, 3.5 ms from NVIDIA's disk cache and 2.1 ms from the driver's memory; keeping all 50,547 predicted pipelines in the game's cache costs about 650 MB a session (about 14.6 KB each).
HumanBean closed this pull request 2026-11-13 02:45:54 +00:00

Pull request closed

Sign in to join this conversation.
No description provided.