Skip to content

Avoid unnecessary evaluations during dotnet run file.cs #49991

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 5 commits into
base: main
Choose a base branch
from

Conversation

jjonescz
Copy link
Member

Part of #48011.

@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Jul 30, 2025
@jjonescz jjonescz marked this pull request as ready for review July 30, 2025 15:22
@Copilot Copilot AI review requested due to automatic review settings July 30, 2025 15:22
@jjonescz jjonescz requested a review from a team as a code owner July 30, 2025 15:22
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR optimizes the dotnet run file.cs command by avoiding unnecessary MSBuild evaluations when run properties can be cached or reused from previous builds. The changes focus on caching run properties during builds and reusing them to skip expensive project evaluations.

Key changes include:

  • Enhanced caching mechanism to store and reuse run properties from previous builds
  • Modified run command logic to use cached properties when available instead of re-evaluating projects
  • Updated test expectations to reflect the reduced number of MSBuild evaluations

Reviewed Changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Added tests for ComputeRunArguments target and updated binary log expectations to reflect fewer MSBuild invocations
src/Cli/dotnet/Commands/Test/TestApplication.cs Updated property names from Run* to simpler names in RunProperties
src/Cli/dotnet/Commands/Test/SolutionAndProjectUtility.cs Updated RunProperties property references and method calls
src/Cli/dotnet/Commands/Test/MSBuildHandler.cs Updated logging to use new RunProperties property names
src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs Enhanced caching logic to store run properties and avoid re-evaluation
src/Cli/dotnet/Commands/Run/RunProperties.cs Expanded RunProperties to include additional metadata and restructured creation methods
src/Cli/dotnet/Commands/Run/RunCommand.cs Modified to use cached run properties when available instead of always evaluating projects
src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs Removed redundant verbose logging that's now handled elsewhere
src/Cli/dotnet/Commands/Run/Api/RunApiCommand.cs Updated method call to match new signature
src/Cli/dotnet/Commands/Restore/RestoringCommand.cs Updated method name to use plural form
src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildArgs.cs Generalized method to accept multiple targets instead of single target
Comments suppressed due to low confidence (1)

src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs:205

  • This debug assertion was removed but the logic it was protecting against may still be relevant. If the combination of NoRestore and NoBuild is invalid, this should be validated elsewhere or the removal should be explained.
        var verbosity = MSBuildArgs.Verbosity ?? VerbosityOptions.quiet;

@jjonescz jjonescz requested a review from a team July 30, 2025 15:23
if (applicationArgs.Length != 0)
{
runArguments += " " + ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(applicationArgs);
return this with { Arguments = Arguments + " " + ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(applicationArgs) };
Copy link
Member

Choose a reason for hiding this comment

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

... That's interesting syntax. Can you use with on anything or just this?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

also any struct type.

}

MarkBuildStart();
}
else
else // if (NoBuild)
Copy link
Member

Choose a reason for hiding this comment

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

nit: commented code

Copy link
Member Author

Choose a reason for hiding this comment

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

That's not commented code, that's my attempt at making it clearer what "state" the else branch is in since it's a bit far away from the if (!NoBuild) above.

Copy link
Member

Choose a reason for hiding this comment

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

It may be easier to follow if the condition were inverted since the 'else' would be closer to the 'if' in that case. However, there isn't a need to make a change here.

@RikkiGibson RikkiGibson self-assigned this Jul 31, 2025
FacadeLogger? logger = LoggerUtility.DetermineBinlogger([..MSBuildArgs.OtherMSBuildArgs], "dotnet-run");
if (cachedRunProperties != null)
{
// We can also skip project evaluation if we already evaluated the project during virtual build
Copy link
Member

Choose a reason for hiding this comment

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

"virtual build" means when csc is invoked directly?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it's referring to the VirtualProjectBuildingCommand invoking MSBuild on a "virtual" project. Then we get cachedRunProperties from there.

@@ -969,7 +1017,7 @@ public void BinaryLog_ArgumentForms(string arg)
new DirectoryInfo(testInstance.Path)
.EnumerateFiles("*.binlog", SearchOption.TopDirectoryOnly)
.Select(f => f.Name)
.Should().BeEquivalentTo([$"{fileName}.binlog", $"{fileName}-dotnet-run.binlog"]);
.Should().BeEquivalentTo([$"{fileName}.binlog"]);
Copy link
Member

Choose a reason for hiding this comment

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

Is the second binlog just something we never need any more?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct (for file-based apps only, project-based apps are unchanged). That dotnet-run.binlog was used when building the "ComputeRunArguments" target separately, but it's all in one binlog now.

}

MarkBuildStart();
}
else
else // if (NoBuild)
Copy link
Member

Choose a reason for hiding this comment

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

It may be easier to follow if the condition were inverted since the 'else' would be closer to the 'if' in that case. However, there isn't a need to make a change here.

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.

4 participants