Skip to content

Improving dotnet run file.cs performance #48011

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
DamianEdwards opened this issue Mar 29, 2025 · 2 comments
Open

Improving dotnet run file.cs performance #48011

DamianEdwards opened this issue Mar 29, 2025 · 2 comments
Labels
Area-CLI Area-run-file Items related to the "dotnet run <file>" effort
Milestone

Comments

@DamianEdwards
Copy link
Member

DamianEdwards commented Mar 29, 2025

Issue to capture data, ideas, etc. regarding improving the DX performance of the new dotnet run file.cs feature. Specific work item issues can be added as sub-issues to this epic.

Some baseline numbers

Windows & WSL2 numbers measured on the same machine. Mac numbers measured on an M4 Mac Mini. Both Windows & Mac machines enrolled in corporate device management.

Command OS Time Notes
dotnet --list-sdks Windows ~12-20ms No managed runtime involved so extremely fast listing of SDK directories in known location
dotnet --list-sdks Ubuntu via WSL2 ~5ms
dotnet --list-sdks macOS ~17-20ms
dotnet run --help Windows ~200ms Loads the CLI and dispatches to the run command. Basically as fast as an invocation of dotnet run can be. Anything we can do to reduce this should improve the DX of dotnet run file.cs too.
dotnet run --help Ubuntu via WSL2 ~112ms
dotnet run --help macOS ~144ms
dotnet exec hello.dll Windows ~32ms Full run of a built hello world console app (default Debug configuration). Anything more than this is DX overhead.
dotnet exec hello.dll Ubuntu via WSL2 ~31ms Interestingly this is the only case where the number is basically the same between Windows and Ubuntu
dotnet exec hello.dll macOS ~54ms This was consistently slower than launching on my Windows/WSL2 machine

Windows vs. Linux (WSL)

I did some comparisons of running dotnet run hello.cs on various Windows 11 machines (both Intuned and not Intuned, desktops and laptops) vs. running it in a WSL2 Ubuntu instance on those same machines. In each case, the .NET CLI was installed into the Linux instance and the test C# files were in the Linux file system directly rather than accessed via the host.

In all cases, running dotnet run hello.cs in the WSL instance was significantly faster, usually around 40-50% faster but sometimes even more. On my laptop It usually took around 2-2.5 seconds in Windows, and in WSL it took only 1.1-1.2 seconds. On my desktops the numbers were more like Windows 1.5 seconds, WSL 1.0 seconds.

This pattern was consistent whether running with real-time antivirus inspection enabled or disabled (either via directory exclusions or by completely disabling it).

Not sure what action we can take other than profiling to help isolate the differences but the data seemed interesting to record.

Build vs. no-build

The overhead of performing a build (i.e. using MSBuild) during dotnet run hello.cs is significant. Directly comparing dotnet run hello.cs to dotnet run hello.cs --no-build results in times like the following (all measurements taken on the same machine):

Command OS Time
dotnet run file.cs Windows ~1.5s
dotnet run file.cs --no-build Windows ~630ms
dotnet run file.cs Ubuntu via WSL2 ~830ms
dotnet run file.cs --no-build Ubuntu via WSL2 ~330ms

It seems it will be extremely beneficial to explore ways in which we can speed up the build step, or completely avoid it when possible, given the more scoped set of changes that might occur between runs of a specific C# file, e.g.:

  • Enabling of the MSBuild server is planned later in the .NET 10 cycle & could improve build times
  • Caching of the RAR task outputs has been discussed and could improve build times
  • runfile could completely avoid running build if there are no implicit build files and no C# file directives (i.e. #:sdk and #:package) as the set of inputs to the compiler is fixed (e.g. at CLI build time) and could be invoked directly
  • runfile could implement up-to-date checks (modified time stamps, content hashes) on build-effecting inputs like implicit build files, C# files, and C# file directives and when no build-impacting changes are detected directly invoke the compiler using cached arguments from the previous run.
    • Adding or deleting a C# file would likely need to be considered a change that requires re-invoking build as globs are evaluated as part of the build, but non-directive changes to C# files should be fine
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-CLI untriaged Request triage from a team member labels Mar 29, 2025
@DamianEdwards DamianEdwards added Area-run-file Items related to the "dotnet run <file>" effort and removed untriaged Request triage from a team member labels Mar 29, 2025
@DamianEdwards DamianEdwards added this to the 10.0.1xx milestone Mar 29, 2025
@agocke
Copy link
Member

agocke commented Apr 1, 2025

cc @jaredpar

@jaredpar
Copy link
Member

jaredpar commented Apr 2, 2025

I'm really hoping that in the majority case we can skip the build step altogether. Consider for example the idea of going up to a directory on your machine, typing up a quick app.cs file and executing dotnet run app.cs. In that example, why do we need to invoke msbuild at all? The reason for using msbuild here is to find the rsp file that needs to be passed to the compiler. The content of that rsp, modulo absolute paths, is known at the time we create the .NET SDK. For situations like that we could just have the RSP pre-generated and do some quick path replacements and skip msbuild altogether.

Think the idea of caching and re-using RSP files for the compiler is something that could benefit us here in even more scenarios.

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

No branches or pull requests

3 participants