Skip to content

Conversation

@majocha
Copy link
Contributor

@majocha majocha commented Nov 26, 2025

Description

The expensive part is generation of structural keys out of TTypes. This was optimized before by memoizing the structures of solved rigid TTypes. We can't do that if the TType is unsolved or there is a chance it will mutate. Unfortunately to find out if a type is rigid we need to traverse it's structure anyway.

  • sped up structure generation overall by passing a ResizeArray accumulator, pooling some objects and making TypeToken more GC friendly.
  • treat IsFromError type vars as stable.

Improves #19116

Checklist

  • Test cases added
  • Performance benchmarks added in case of performance changes
  • Release notes entry updated:

@github-actions
Copy link
Contributor

github-actions bot commented Nov 26, 2025

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/10.0.200.md

majocha and others added 2 commits November 26, 2025 11:25
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
@majocha
Copy link
Contributor Author

majocha commented Nov 26, 2025

I tested this by building the problematic branch of FSharpPlus:

gh pr checkout 614
dotnet build .\tests\FSharpPlus.Tests\ -bl -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\bin\fsc\Release\net10.0\fsc.dll --no-incremental

and verified it now manages to finish after a good coffee break.

The code in this PR is 100% Gemini 3 via Copilot with only textual prompts.

@majocha
Copy link
Contributor Author

majocha commented Nov 26, 2025

This needs a double check that other scenarios are not degraded now.

@majocha
Copy link
Contributor Author

majocha commented Nov 26, 2025

Very informal speed test, because it takes ages:
FSharpPlus repo

gh pr checkout 614
dotnet build .\tests\FSharpPlus.Tests\ -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\Bootstrap\fsc\fsc.dll --no-incremental

fsc.dll from main: 630.0s

fsc.dll from main with langversion 9.0 (which means cache disabled): 368.3s

fsc.dll from this PR (back to langversion 10.0): 401.9s

@majocha
Copy link
Contributor Author

majocha commented Nov 26, 2025

Compiling just FSharpPlus project without tests, caching starts to pay off:

main:

dotnet build .\src\FSharpPlus\ -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\Bootstrap\fsc\fsc.dll --no-incremental

Restore complete (0.2s)
  FSharpPlus net8.0 succeeded (105.4s) → src\FSharpPlus\bin\Debug\net8.0\FSharpPlus.dll

Build succeeded in 105.9s

main langversion 9:

dotnet build .\src\FSharpPlus\ -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\Bootstrap\fsc\fsc.dll --no-incremental

Restore complete (0.2s)
  FSharpPlus net8.0 succeeded with 1 warning(s) (101.9s) → src\FSharpPlus\bin\Debug\net8.0\FSharpPlus.dll
    E:\repos\FSharpPlus\src\FSharpPlus\Builders.fs(12,1): warning FS0236: Directives inside modules are ignored

Build succeeded with 1 warning(s) in 102.4s


this PR:

dotnet build .\src\FSharpPlus\ -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\Bootstrap\fsc\fsc.dll --no-incremental

Restore complete (0.2s)
  FSharpPlus net8.0 succeeded (64.2s) → src\FSharpPlus\bin\Debug\net8.0\FSharpPlus.dll

Build succeeded in 64.7s

@T-Gro
Copy link
Member

T-Gro commented Nov 27, 2025

The timings are really great, the escape hatch via the cooldown is a nice amortization trick to find a balance between benefiting the cache vs. not being significantly slower than before.

👍

@T-Gro
Copy link
Member

T-Gro commented Nov 27, 2025

Very informal speed test, because it takes ages: FSharpPlus repo

gh pr checkout 614
dotnet build .\tests\FSharpPlus.Tests\ -p:DotnetFscCompilerPath=E:\repos\fsharp\artifacts\Bootstrap\fsc\fsc.dll --no-incremental

fsc.dll from main: 630.0s

fsc.dll from main with langversion 9.0 (which means cache disabled): 368.3s

fsc.dll from this PR (back to langversion 10.0): 401.9s

Does it finish building the .Tests project successfully, or does it fail somewhere along the way?

@majocha
Copy link
Contributor Author

majocha commented Nov 27, 2025

I had to remove the cooldown (but the times measured are without it), it was very bad on other scenarios (OpenTK), but the optimizations copilot did are still very worthwhile.

I did some measurements, and it turns out at best around 50% of emitted type structures are weakly cached. In case of FSharpPlus it amounts to many millions of calls, so optimizing this can really pay off.

Does it finish building the .Tests project successfully, or does it fail somewhere along the way?

It fails, but it fails consistently, same errors on main as this PR.

@majocha
Copy link
Contributor Author

majocha commented Nov 27, 2025

This is pretty much done. TypeToken struct should take a bit less memory.

Timings are passable:
image
Memory use is under control, so this should not hang anymore.

@github-project-automation github-project-automation bot moved this from New to In Progress in F# Compiler and Tooling Nov 28, 2025
@T-Gro T-Gro enabled auto-merge (squash) November 28, 2025 09:39
@T-Gro T-Gro merged commit 0e96924 into dotnet:main Nov 28, 2025
38 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in F# Compiler and Tooling Nov 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants