rust test: Parallelize Slint compiler execution (and fix a stack usage hotspot) - #12691
Merged
Conversation
…ript The build script processed the test cases sequentially. With the build-time feature each case runs the Slint compiler, twice with deterministic-output, which made the script the longest single unit of the integration test build in CI: 287 seconds on the 4-core Windows runner, during which the dependent test binaries cannot start compiling. Distribute the cases over all cores with rayon. par_iter preserves the input order, so the module declarations in the generated files don't depend on thread scheduling. compile_syntax_node is thread safe. The 512KB stack size that compile_and_generate applied with a dedicated thread per compiler call is set on the pool workers instead. A dedicated pool with install() is used rather than the global pool, because with the global pool the calling thread also executes jobs on its own large stack, which would exempt some cases from the small-stack check. The generated output is byte-identical to the sequential version for the full test corpus (822 files). On a 24-core machine the script goes from 160 to 13 seconds.
process_expression recursed with an 18KB stack frame in debug builds: the function held the temporaries of every match arm, and debug builds give each temporary its own stack slot. A 25-deep else-if chain was enough to overflow the 512KB stack that the rust test driver uses as a canary for environments with small stacks. Move the heavy arms (Condition, StoreLocalVariable) into their own functions, and split the merging of the processed branches out of process_condition so that its temporaries don't occupy the frame during the recursive calls. A recursion level now needs 4.6KB instead of 18.6KB. The generated code is unchanged; the worst case over the whole rust test corpus now compiles with a 416KB stack instead of 480KB, and the new limiting factor is the resolving pass on long chains of binary operators.
tronical
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The test-driver-rust build script compiled every test case sequentially (twice each, due to the deterministic-output check). It was the longest single unit of the integration test build in CI: 287 seconds on the 4-core Windows runner, during which the dependent test binaries can't start compiling.
This PR distributes the cases over all cores with rayon.
The script drops from 160 s to 13 s on my 24-core machine
(expect ~2.5–3× on CI runners).
Moving the 512 KB small-stack guard from a per-case thread onto the rayon pool exposed that the guard had almost no headroom left. The second commit splits the pass's heavy match arms into separate functions.