extensions icon indicating copy to clipboard operation
extensions copied to clipboard

CSharp compiler is incredibly slow in extensions repo

Open ericstj opened this issue 1 month ago • 6 comments

Build times in dotnet/extensions have really been bugging me lately. All these measurements are made on a devbox with 32vCPU | 128GB | 2048GB

For instance:

C:\src\dotnet\extensions\src\Libraries\Microsoft.Extensions.AI.Abstractions>dotnet build --no-dependencies -f net8.0 /bl
  Microsoft.Extensions.AI.Abstractions net8.0 succeeded (10.1s) → ..\..\..\artifacts\bin\Microsoft.Extensions.AI.Abstractions\Debug\net8.0\Microsoft.Extensions.AI.Abstractions.dll

Build succeeded in 10.6s

That's 10 seconds to build a single assembly ( ~10K LOC, 100 files) for a single target framework without any dependencies! Now I can specify /p:SkipAnalyzers=true to avoid this (still 2-4s), but that risks building debt with the code I write that will fail analysis when it comes time to submit.

So I tried to see what was causing it.

Rebuild with

dotnet build --no-dependencies -f net8.0 /bl /p:ReportAnalyzer=true
Image

Impressive that these can take more time than the build itself. I think that's because it's summing the work across multiple threads.

The biggest culprit is

 29.868   52      SonarAnalyzer.Rules.CSharp.SymbolicExecutionRunner (S1944, S2053, S2222, S2259, S2583, S2589, S3329, S3655, S3900, S3966, S4158, S5773)

I saw we were using an old copy of this analyzer. I upgrade to the latest from NuGet and see the same perf issue. It helped a little, but not completely.

C:\src\dotnet\extensions\src\Libraries\Microsoft.Extensions.AI.Abstractions>dotnet build --no-dependencies -f net8.0 /bl /p:ReportAnalyzer=true
  Microsoft.Extensions.AI.Abstractions net8.0 succeeded (9.5s) → ..\..\..\artifacts\bin\Microsoft.Extensions.AI.Abstractions\Debug\net8.0\Microsoft.Extensions.AI.Abstractions.dll

Build succeeded in 10.0s

That seemed to help a bit: Image

But still not great. I tried disabling those sonar analyzers completely, but it didn't make a difference (at least after updating them).

I can reduce the time by about 5 seconds but disabling this analyzer: https://github.com/dotnet/extensions/blob/a2d763f31e2114f0e4c514bef01d9e676d91c1df/src/Libraries/.editorconfig#L497-L500 Which should be fine, since it's suggestion anyhow.

The following two are the next up, which gave me another 2s wall clock time: https://github.com/dotnet/extensions/blob/a2d763f31e2114f0e4c514bef01d9e676d91c1df/src/Libraries/.editorconfig#L945-L948 https://github.com/dotnet/extensions/blob/a2d763f31e2114f0e4c514bef01d9e676d91c1df/src/Libraries/.editorconfig#L328-L331 Those give value though, so I wouldn't really want to disable them.

Some of this seems like simple improvements we can do to improve the dev-time, but I'm still surprised at how bad the perf is even after that. cc @stephentoub @jeffhandley @joperezr

ericstj avatar Nov 04 '25 18:11 ericstj

FWIW, I personally would have zero qualms with removing the sonar analyzers completely.

I can reduce the time by about 5 seconds but disabling this analyzer:

I'm surprised analyzers at the suggestion level are running at all in a command-line build.

stephentoub avatar Nov 04 '25 19:11 stephentoub

I couldn't find anything that would make suggestion analyzers not run during CLI builds (and copilot agrees). I opened a feature request.

ericstj avatar Nov 04 '25 19:11 ericstj

I'm unsure whether it would help your scenario, but, wanted to note that Roslyn disables analyzers in certain local and CI builds.

https://github.com/dotnet/roslyn/blob/4eb427dfc66e72b855642d3f7ece3f5bb90adaee/eng/targets/Imports.targets#L56-L70

For example, with local builds, the developer needs to pass build.cmd -runAnalyzers or dotnet build /p:RunAnalyzersDuringBuild=true to see analyzer diagnostics.

The analyzer diagnostics still appear in the editor, though, so in most cases, we don't have too many problems with only finding out about analyzer issues once the CI run finishes.

RikkiGibson avatar Nov 04 '25 19:11 RikkiGibson

We could choose to invert the default, but that still makes official builds slow, which we also care about. I also worry that if we change the default to be different than what our customers see we might not find the bugs in the product our customers care about. It could be that some of these analyzers have performance issues that need to be fixed.

ericstj avatar Nov 04 '25 22:11 ericstj

Thanks for raising this, @ericstj. This problem is now even more noticeable since we just added a new TFM to all of the libraries, so build times just got worse by an order of magnitude. After 10.0 ships, I'm open to having a discussion on which analyzers provide value and should be kept, vs which ones should potentially be removed or disabled by default and perhaps just run on CI.

joperezr avatar Nov 04 '25 23:11 joperezr

I'm not convinced that there aren't product bugs in some of these analyzers, so we should try to understand if that's the case. CA11508 - Avoid dead conditional code for example - why should the execution of that analyzer ever contribute to 5s in a 10s build of an assembly?

ericstj avatar Nov 05 '25 19:11 ericstj