-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Adapt System.CommandLine (v2) in more places #72082
Adapt System.CommandLine (v2) in more places #72082
Conversation
Do you have stats for crossgenning a hello world? The main problem with S.CommandLine was startup time. CoreLib is a huge assembly and not very representative of what we're crossgenning normally. Most assemblies are a lot smaller than CoreLib. Last time we were looking at S.CommandLine, the startup overhead for compiling hello world was like 25%. |
@MichalStrehovsky, I was motivated by aot related improvements made in System.CommandLine. The speed overhead is becoming insignificant. helloworld script: $ /runtime/dotnet.sh \
/runtime/artifacts/bin/coreclr/Linux.x64.Release/crossgen2/crossgen2.dll \
-o:./helloworld.ni.dll \
-r:/runtime/artifacts/bin/coreclr/Linux.x64.Release/IL/*.dll \
--targetarch:x64 -O --verify-type-and-field-layout \
/helloworld/bin/Release/net7.0/helloworld.dll \
--perfmap-format-version:1 --perfmap --perfmap-path:/tmp/ Results from 100 iterations:
|
@@ -0,0 +1,289 @@ | |||
// Licensed to the .NET Foundation under one or more agreements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is derived from Common/CommandLine/CommandLineHelpers.cs
. The main difference is that it doesn't depend on anything from Common/CommandLine/*
and LINQ. The MakeReproPackage
method in this file uses System.CommandLine's ParseResult
instead of Internal.CommandLine's ArgumentSyntax
.
In a follow-up PR, I will delete src/coreclr/tools/Common/CommandLine/*
after switching dotnet-pgo (its last consumer) to System.CommandLine. ILVerify will also be switched to use this helper during that work (without the need for <DefineConstants>ILVerify
, #if ILVERIFY
).
cc @jkotas, @MichalStrehovsky, PTAL. Diffs without whitespace change will make it a bit easier to review. I switched to use file level namespace in Program.cs to decrease the overall indentation,
Should we align them? |
That should be separate change. We want to be consistent across the whole repro - either agree to do it everywhere or keep it as is. |
@@ -14,6 +14,7 @@ public enum TargetArchitecture | |||
Unknown, | |||
ARM, | |||
ARM64, | |||
ARMEL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this used for?
This would mean that all places the check for TargetArchitecture.ARM
have to check for TargetArchitecture.ARMEL
too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used for (easier) strongly typed binding. In Program.ctor, it overrides ARMEL
-> ARM
since the rest of the implementation expects it with a flag to indicate if ARMEL
ABI is to be used.
Alternatively, I can use the old approach to capture the flag during parsing (it is already using custom step in call to Option<T>
ctor for --targetarch).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would be better - since we do not expect this value to be valid, except in command line parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW #43706 (comment) is the previous conversation on why we don't have TargetArchitecture.Armel.
ilc: --insructionset, crossgen2: --instruction-set Yes, I think it makes sense to align these. |
Sure, I will revert it.
I will update ILC to use |
No pushback from me, the perf results look reasonable, I believe we can take it for .NET 7. |
perhaps we should run the crossgen2 outerloop CI to ensure it doesn't regress anything? |
a0112eb
to
f896f93
Compare
So now it's about 3-4% slower E2E than with Internal.CommandLine. It's probably not blocking anymore. I would certainly not mind if it was faster though - Internal.CommandLine has similar ergonomics and feels like a fair benchmark. For completeness, here's the size: crossgen2 trimmed, compiled with R2R: 33,472,412 bytes -> 34,388,937 bytes (2.7% regression) Not blocking either; could be better. |
1MB worth of code just to parse the command line the same way as before feels like a lot. |
Isn't it 0.91 MB (R2R) and 0.87 MB (AoT) of difference? |
Yes, I was rounding it. (Also, the existing lightweight parser is some code too.) |
Ah, I am sorry. I was reading it on a smaller screen and read it as I agree that we should continue to improve System.CommandLine (size, memory and speed), following the footsteps of @adamsitnik. 😎 |
I don't know much about how satellite assemblies work - would it be sufficient to have a mode in illink that simply doesn't copy these over? illink currently copies all of these over if a ResourceManager..ctor call is seen. I've also filed dotnet/command-line-api#1800 in the command line repo to make the satellite assemblies smaller. 5% of the size of these assemblies is a pompous assembly description that doesn't need to be there. |
In case you want to avoid pulling in the extra satellite assemblies and just a default locale, you can set the following in the project file: https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#satelliteresourcelanguages |
Nice! #72478 |
I just hit the same assertion failure running crossgen2 with GCStress=3 on Windows ARM64 (without this PR). |
@AntonLapounov - is the failure deterministic? I suspect it's worth investigating, I'm just wondering how hard it is to repro. |
It took more than one day on my old ARM64 laptop to hit this. I have a dump if anyone is interested. |
One more thing I noticed is that if the root command has arguments (like in this case the list of input files), System.CommandLine will send all unmatched command line switches as the file names instead of erroring out. I don't know if there's a way not to do that. So The Internal.CommandLine parser that we use right now will instead tell the user that |
I think we shouldn't care about user experience of crossgen2.exe any more than dotnet.exe (that uses System.CommandLine and has much vaster public usage). Of course if we can configure the behavior of the open ended args, that would be nice. To wit: $ ~/.dotnet8/dotnet --foo
The command could not be loaded, possibly because:
* You intended to execute a .NET application:
The application '--foo' does not exist.
* You intended to execute a .NET SDK command:
No .NET SDKs were found.
|
Resolved merge conflicts and unified @jkotas, tree is opened for .NET 8, should we get this in? |
There are ongoing discussions about the future of System.CommandLine. I would prefer for to wait for those discussions to come to conclusion. |
ILVerify, R2Rdump etc. are depending on the same SystemCommandLine package. Getting this in will make it easier to upgrade all dependents to System.CommandLine's future release, when it's time to update the package. tbh, merge conflicts in this PR are not fun to resolve. |
It should be able to handle this, @MichalStrehovsky. I couldn't reproduce the issue. Configuring more specific expected types and adding validators might help. If the parser is throwing an exception, that's unambiguously a bug. Do you have a stack trace for this issue? |
It prints |
@jonsequitur I have opened dotnet/command-line-api#1860 on this |
It is not necessary correct. It can be more work to update the package if there are breaking changes. I agree with that there are number of tools depending on System.CommandLine, and having two more is not going to change the update problem much. So let's get this merged. There is a lot of runway in .NET 8 to get the issues sorted out. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Continuation of #66929; switches ilc and crossgen2 to System.CommandLine.
In 4731fdb, CG2 was switched from System.CommandLine (v1) to an internal CommandLine utility. Since then, the performance and memory consumption in System.CommandLine has improved quite a lot (in the effort to make it AoT friendly). SDK and some tools in runtime repo are already using System.CommandLine v2 beta4.
I did some quick testing in bash by running System.Private.CoreLib's crossgen'ing common (captured from clr subset build):
$ cat cmd.sh /runtime/dotnet.sh \ /runtime/artifacts/bin/coreclr/Linux.x64.Debug/crossgen2/crossgen2.dll \ -o:/runtime/artifacts/bin/coreclr/Linux.x64.Debug/System.Private.CoreLib.dll \ -r:/runtime/artifacts/bin/coreclr/Linux.x64.Debug/IL/*.dll \ --targetarch:x64 -O --verify-type-and-field-layout \ /runtime/artifacts/bin/coreclr/Linux.x64.Debug/IL/System.Private.CoreLib.dll \ --perfmap-format-version:1 --perfmap --perfmap-path:/runtime/artifacts/bin/coreclr/Linux.x64.Debug/
then used GNU's time command to get process-level stats (10 iterations):
Results:
speed is pretty much in noise range; memory and I/O has slightly improved as we are now accessing options lazily from
ParseResult
(in most cases).The last tool on internal plan is dotnet-pgo. If this PR gets accepted, I will work on that and delete the internal utility in a follow-up PR.