dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.87k stars 780 forks source link

F# compiler is really slow when trying to compile .net8.0 project with SDK 8.0.303 #17501

Open NogginBops opened 1 month ago

NogginBops commented 1 month ago

Repro steps

Provide the steps required to reproduce the problem:

  1. Clone this specific commit: https://github.com/BoyBaykiller/opentk/tree/5c9dc6e6f0ec4c911fe05357dbfccc7e81d1842f
  2. Try to compile this test project using dotnet build -v:n .\tests\OpenTK.Tests\OpenTK.Tests.fsproj

Expected behavior

The compiler should compile the project (this particular commit has a runtime error, but that shouldn't matter).

Actual behavior

The compiler never finishes compiling the project.

Known workarounds

Switching to .net6.0 fixes the issue.

Related information

I also tried targeting and compiling the project with SDK Version: 9.0.100-preview.6.24328.19 and I still get the hang.

Provide any related information (optional):

vzarytovskii commented 1 month ago

So, the bad news is that I can't reproduce it on my mac, on both net7.0 and net8.0 as targets, compilation takes about a minute (47-55 seconds) on my machine (M2 macbook). net6.0 in main with the same SDK (8.0.100) takes about 4 seconds, which leads me to believe that it is the same sort of issue as described in https://github.com/fsprojects/Fleece/issues/146.

TL;DR of the issue is: around .NET7 BCL rolled out "Static abstracts in interfaces" feature (which led to much bigger interfaces hirearchy), at the same time we rolled out support for static abstracts as well as some changes to SRTPs. And what I think is happening is that once you introduce new BCL, some of the functionality in your tests is making typechecking go brrr, and performance degrades significantly, see discussion in the issue above, as well as Don's comment in https://github.com/fsharp/fslang-design/commit/71cd2e04bc181264a6a68c731ff018369848d1f9.

Conclusion: with all this in mind, the the best current course of action (for us or contributors) would be to:

  1. Take current compiler from main.
  2. Build it (Release).
  3. Create a global.json file pointing to latest .NET9 SDK (preview 6 at the moment of me commenting it).
  4. Include it in the project from OP (tests project, from master branch, point to custom compiler via UseLocalCompiler.Directory.Build.props importing).
  5. Profile it with net6.0 (default) target.
  6. Change target to net8.0 (or switch branch to otk5-add-matrx-simd-equal, bba4019df27b0a54ff48ca2205d681dbe990824b at the moment of me commenting it).
  7. Include custom compiler there again. Profile it again.
  8. See what's different/what's wrong.
  9. Try to make it better.

As a temporary workaround(s), there were some comments from @gusty in the original issue in Fleece, which might help.

vzarytovskii commented 1 month ago

The worst part is that the more people will move to net8.0 as TFM, the more people might hit this issue. I will try to collect some profiles once I have some free time, unless someone will beat me to it.

vzarytovskii commented 1 month ago

Profiles for

  1. master branch with tests project upgraded to net6.0: net6.zip
  2. otk5-add-matrx-simd-equal branch built with no changes (net8.0): net8.zip

Running via .NET9p6 runtime host, with net8 SDK assemblies, on latest main of compiler.

In case if someone wants to look at it.

vzarytovskii commented 1 month ago

Compiler spent a minute (out of ~2 under profiling) in just getting interfaces for all types:

image

Additionally, some type directed conversions are involved:

image

(I presume, when we try to find conversions we need to traverse all interfaces)

vzarytovskii commented 1 month ago

I will experiment with caching stuff more once I'm off of work.