Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Skip MSBuild and call only CSC for simple file-based apps #49528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Jun 23, 2025

Part of #48011.

With this PR, simple file-based apps (with no #: directives, no implicit build files, no command-line -property switches) use C# compiler (via the compiler server), skipping MSBuild altogether. That can improve time of dotnet run file.cs significantly as the following table shows.

Build level Compiler server Windows Linux
msbuild Killed 10.0 s 7.5 s
csc Killed 7.0 s 4.5 s
msbuild Running 4.0 s 3.0 s
csc Running 0.8 s 0.5 s
no build - 1.0 s 1.0 s

(UPDATE: Figured out that "no build" is slower than "csc" because the csc optimized path doesn't need to invoke MSBuild to do project evaluation to figure out the target command to run, whereas the no-build path still does that. I will look into improving that in a follow up.)

The next step will be to skip MSBuild for more complex file-based apps as well (by reusing csc arguments from the previous msbuild run).

Resolves #49478 (sdk and runtime version is now included in the cache and build isn't skipped if those are different between the previous and current run).

@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Jun 24, 2025
@jjonescz jjonescz force-pushed the sprint-perf-2 branch 2 times, most recently from 272c4ca to e9eae7a Compare June 24, 2025 13:01
@@ -32,6 +32,7 @@
<add key="richnav" value="https://pkgs.dev.azure.com/azure-public/vside/_packaging/vs-buildservices/nuget/v3/index.json" />
<!-- mstest dependencies -->
<add key="test-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/test-tools/nuget/v3/index.json" />
<add key="temporary" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 This should go away before the PR is merged. I'm using this to get a test build of the BuildClient package before dotnet/roslyn#78986 is merged and we have an official build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@jjonescz jjonescz marked this pull request as ready for review June 24, 2025 14:53
@jjonescz jjonescz requested a review from a team June 24, 2025 14:53
Copy link
Member

@MiYanni MiYanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concern: How is output handled? MSBuild has lots of handling of error situations and things. So, skipping that, what do we see when doing certain "normal" failure scenarios? I see some of the tests handle some of the CS#### errors. I'm not familiar with how/if MSBuild translates or supersedes those.

@jjonescz
Copy link
Member Author

jjonescz commented Jul 1, 2025

@RikkiGibson @chsienki @jaredpar for reviews, thanks

@RikkiGibson RikkiGibson self-assigned this Jul 1, 2025
@jaredpar jaredpar added this to the 10.0.1xx milestone Jul 1, 2025
Directory.CreateDirectory(binDir);

string assemblyAttributes = Path.Join(objDir, $".NETCoreApp,Version=v{TargetFrameworkVersion}.AssemblyAttributes.cs");
if (ShouldEmit(assemblyAttributes))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain why we need the ability to create the auxiliary files here? I was hoping these would just be on disk from a previous msbuild run, and if they are not, then we just run msbuild and save the csc optimization for the next time.

Copy link
Member Author

@jjonescz jjonescz Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The motivation for this optimization is to make even the first run faster as per @jaredpar's comment: #48011 (comment).

The limitation is that only simple apps can be optimized like this (due to the need of hard-coding the csc arguments and the auxiliary files). The advantage is that even the first run is fast. Next, though, I'd like to add an optimization where msbuild results would be re-used like you say and that should work for any apps. We won't need to hard-code any auxiliary files nor csc arguments for those (we can just extract them from the prior msbuild run), but they don't work on the first run. Both optimizations can work side-by-side in different scenarios.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I buy this, thanks. I am using file-based apps with no directives a significant amount already.

I am interested to see how it works in practice, as we insert new compilers, new versions of standard references get introduced, etc. and the arguments evolve. Possibly there will be various PRs where we just need to jump in and rerun the generator. And since this is the type of codegen that we would really like to manually review, it seems good for the generated code to be version controlled, require an explicit step to change it, and so on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...should we just encode this generation into an MSBuild Target? It should be pretty easy to make a one-off task in the src/Layout/redist.csproj Targets that

  • builds a 'simple' .NET app using the targets in the SDK's 'stage 2' SDK layout
  • grabs the CSC command line from that (it's available as a project/etc)
  • writes that data to whatever file you need

and does so in a highly-incremental way to not impact inner loop builds too badly.

Copy link
Member Author

@jjonescz jjonescz Jul 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we just encode this generation into an MSBuild Target?

I've considered that and I chose the current approach so that changes in the generated code need to be reviewed since they are included in Git (as Rikki also mentioned).1 Mainly because I'm not 100% confident that the code generator is perfect and hence I'd like to see how the generated code changes over time, at least in the beginning, we can move it to be a more automatic part of the build process (via a Target) later if that sounds good to you?

Note that we have a prior work: CLI completion snapshots are also generated by tests.

builds a 'simple' .NET app using the targets in the SDK's 'stage 2' SDK layout

Wouldn't this mean that the generated code couldn't be included in the SDK which is being built because the CLI DLL is already built at this point?

Footnotes

  1. If the generated code came from a target, presumably that wouldn't be Git-tracked (otherwise I'm not sure what would be the advantage of a Target over a test).

Copy link
Member

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some questions and minor comments.

@jjonescz
Copy link
Member Author

jjonescz commented Jul 4, 2025

@jaredpar @chsienki for another review, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-run-file Items related to the "dotnet run <file>" effort
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Runtime version should be part of file-based app cache
5 participants