Search code examples
c#.netcompilationroslyncsc

csc.exe compilation time degradation when "Microsoft.CodeDom.Providers.DotNetCompilerPlatform" package is used


Our team is currently migrating from C# 5.0 to C# 6.0 syntax so Roslyn compiler should be used instead of the legacy one.

We have to use "csc.exe" as a part of the complex solution compilation process. Build commands look like this:

c:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe -nologo -target:library  -out:c:\repo\bin64\deb\common.dll @.\rspE0FF.tmp

This command execution takes ~400ms

"rspE0FF.tmp" content looks like this (it contains much more *.cs files, however, it does not matter, this is reproducible on any set of files):

"c:\repo\shared\common\estimation\complexjob.cs"
"c:\repo\shared\common\stringdecorator.cs"
"c:\repo\shared\common\tplextensions.cs"
"/reference:mscorlib.dll" "/reference:System.dll" "/reference:System.Data.dll" "/reference:System.Xml.dll" "/reference:System.ServiceModel.Activation.dll" "/reference:System.IdentityModel.dll" "/reference:System.Data.Entity.dll" 

When Roslyn compiler is used execution time shouts to ~4100ms Command is the same just csc.exe is called from the package folder:

c:\NewRepo\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\tools\RoslynLatest\csc.exe -nologo -target:library -out:c:\repo\bin64\deb\common.dll @.\rspE0FF.tmp

We have to build the solution by sequentially running hundreds of csc.exe commands like this. Total compilation time has grown from 2 minutes to 8 minutes.

Is this performance degradation expected?

Any advice on how to tweak this?


Solution

  • The roslyn team does not consider someone invoking csc.exe as part of its perf investigations. Today you are jitting all of csc.exe on each invocation (see here for more info).

    Possible solutions:

    • run ngen on the version of csc you are using so hopefully you only need to JIT once
    • use the compiler server, which in addition to re-using csc instances also caches metadata across builds.

    NOTE: the msbuild task does this automatically for you, but in your case you will need to do this manually.

    You would need to setup the server (duplicate what this code is doing) and pass /server to all of your csc calls