Repository navigation
Compile with DOTNET_TieredPGO=0 DOTNET_TC_CallCountingDelayMs=0 for faster compilation #20802
Description
Is your feature request related to a problem? Please describe.
Compilation is slow.
Describe the solution you'd like
Setting DOTNET_TieredPGO=0 DOTNET_TC_CallCountingDelayMs=0 for the compiler process (fsc.dll) can significantly speed it up.
Describe alternatives you've considered
Additional context
At G-Research I have spent considerable time trying to optimise F# compilation times of our large solution (mixed C# + F#).
As part of that I discovered that the following two runtime JIT flags have a large impact on compilation times & CPU time:
DOTNET_TieredPGO=0DOTNET_TC_CallCountingDelayMs=0
Internal tests at G-Research against internal projects showed large speed ups.
We have onboarded these settings in some of our environments.
Today I executed extensive AI-driven multi-hour tests at home against the compiler codebase and saw similar results.
Reports
A few AI-generated reports with varying level of detail:
- Markdown report: https://github.com/safesparrow/fsharp_misc/blob/main/reports/pr/report.md
- HTML version: https://safesparrow.github.io/fsharp_misc/reports/pr/report.html
- Extended HTML report - all other configurations tested, more details and interactive charts: https://safesparrow.github.io/fsharp_misc/reports/report.html
Results summary - AI-generated
- All 14 compilations of
FSharp.Compiler.Service.slnxtogether (newest target framework of each project, parallel compilation on): 63.1 s → 36.3 s wall (−42.5%, 95% CI −43.4% to −41.9%), CPU −31.0% (−32.7% to −29.4%). - Medium and large compilations (6 of 14, 1.5 s to 25 s): wall −56% to −36%, CPU −43% to +2%. FSharp.Compiler.Service itself: 24.4 s → 13.5 s.
- Small compilations (8, under 1.5 s): wall −19% to −3%, but CPU +20% to +49%: the process ends before recompiling startup code pays off.
- Whole
dotnet buildof Fantomas (SDK 11, 6 runs per mode): −18.7% wall with the settings on fsc only - GC pause time is unchanged (−1.1%). JIT CPU time goes up (+202%), mostly on the background tier-1 thread, which is what buys the speed-up.
This vs a compilation server
Note that this is related to the F# compilation server concept that we have been working on.
For server-based compilation, the default runtime settings are adequate and changing them is likely to reduce performance - but server compilation is not yet available, and this could be a nice easy speed up until it is.
Results
The two sections below describe compiling the full compiler solution with 14 projects.
Speed up per project
All large & medium projects show significant wall-clock time and CPU time reduction.
The smallest projects (that compile in ~1s) show slightly reduced wall-clock time and increased CPU time.
Aggregate timings of each compilation phase
| All compilations, sum of medians | Defaults | Flags | Δ (95% CI) |
|---|---|---|---|
| Wall time | 63.1 s | 36.3 s | -42.5% (-43.4 to -41.9) |
| CPU time | 210.0 s | 144.8 s | -31.0% (-32.7 to -29.4) |
| JIT time (all threads) | 9.1 s | 27.6 s | +201.9% (+190.1 to +206.2) |
| GC pause time | 6.1 s | 6.1 s | -1.1% (-2.0 to +0.6) |
| Phase: Import references | 2.9 s | 2.3 s | -19.3% (-20.2 to -18.4) |
| Phase: Parse | 2.2 s | 2.0 s | -7.2% (-8.6 to -5.2) |
| Phase: Typecheck | 23.6 s | 12.2 s | -48.2% (-51.6 to -47.5) |
| Phase: Optimizations | 18.1 s | 9.5 s | -47.3% (-48.2 to -45.4) |
| Phase: TAST -> IL | 5.8 s | 3.6 s | -39.3% (-41.2 to -34.9) |
| Phase: Write .NET binary | 6.1 s | 3.6 s | -41.9% (-42.7 to -39.5) |
| Phase: Other phases | 2.4 s | 1.4 s | -44.3% (-47.0 to -42.2) |
| Phase: Startup & exit | 1.5 s | 1.5 s | +0.1% (-0.8 to +1.0) |
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNew
Activity
safesparrow commentedon Oct 17, 2026
@T-Gro I forgot to discuss these in more detail earlier this week. These are settings that in my testing significantly speed up compilation across all codebases tested, and are a middle ground between the current setup and a future F# compilation server.
As these are completely safe in terms of compilation outputs (determinism etc), it should be easier to get these in.
I will raise an issue for the compilation server separately.
baronfel commentedon Oct 17, 2026
@safesparrow when you say that applying these flags to MSBuild also resulted in wall clock improvements, was that with or without MSBuild Multithreaded Mode (-mt) in use? I'm very curious about mor general build performance improvements too, but with the MSBuild Server (which MT uses) I would expect the tiered compilation to benefit us over time.
safesparrow commentedon Oct 17, 2026
@baronfel Sorry, that was without node reuse, so without the server either - better stability run-to-run, but not actually relevant for judging MSBuild changes.
Please discard that point about MSBuild speed ups. As with the compiler server, long-running processes like MSBuild worker nodes/server should work best with the default settings.
T-Gro commentedon Oct 21, 2026
I see the JIT time went up -> I will test if just disabling QuickJit will bring similar result.
So that precompiled code could still participate when its available (e.g. the BCL).
safesparrow commentedon Oct 22, 2026
Method count per JIT type, from https://safesparrow.github.io/fsharp_misc/reports/report.html#gridSection :