-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Use System.CommandLine (v2) in dotnet-pgo #76467
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
Merged
jkotas
merged 10 commits into
dotnet:main
from
am11:feature/deps/system.commandline_usage
Oct 3, 2022
Merged
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
e7c7051
Use System.CommandLine (v2) in dotnet-pgo
am11 42a1f15
Delete internal CommandLine implementation
am11 9b873dc
Fix release build
am11 9171308
Apply suggestion
am11 775c179
Use BuildPathDictionay helper in input options
am11 1f66d6d
Restore string[] in compare-mibc
am11 ed9dd01
Fix ILVerify build
am11 b1f37e7
Fix typo
am11 e280e32
Merge dotnet/main into feature/deps/system.comman..
am11 f535d32
Add BuildPathList helper
am11 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
Use System.CommandLine (v2) in dotnet-pgo
- Loading branch information
commit e7c70516de4f6befb1a3f262a150f962c4fe8343
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,296 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.CommandLine; | ||
| using System.CommandLine.Help; | ||
| using System.CommandLine.Invocation; | ||
| using System.CommandLine.Parsing; | ||
| using System.Diagnostics; | ||
| using System.IO; | ||
| using System.Reflection; | ||
|
|
||
| namespace Microsoft.Diagnostics.Tools.Pgo | ||
| { | ||
| internal sealed class PgoRootCommand : RootCommand | ||
| { | ||
| public Option<string[]> InputFilesToMerge { get; } = | ||
| new(new[] { "--input", "-i" }, "Input .mibc files to be merged. Multiple input arguments are specified as --input file1.mibc --input file2.mibc") { IsRequired = true, Arity = ArgumentArity.OneOrMore }; | ||
| public Option<string[]> InputFilesToCompare { get; } = | ||
| new(new[] { "--input", "-i" }, "The input .mibc files to be compared. Specify as --input file1.mibc --input file2.mibc") { IsRequired = true, Arity = new ArgumentArity(2, 2) /* exactly two */ }; | ||
| public Option<string> InputFileToDump { get; } = | ||
| new(new[] { "--input", "-i" }, "Name of the input mibc file to dump") { IsRequired = true, Arity = ArgumentArity.ExactlyOne }; | ||
am11 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public Option<string> TraceFilePath { get; } = | ||
| new(new[] { "--trace", "-t" }, "Specify the trace file to be parsed"); | ||
| public Option<string> OutputFilePath { get; } = | ||
| new(new[] { "--output", "-o" }, "Specify the output filename to be created"); | ||
| public Option<string> PreciseDebugInfoFile { get; } = | ||
| new(new[] { "--precise-debug-info-file" }, "Name of file of newline separated JSON objects containing precise debug info"); | ||
| public Option<int> Pid { get; } = | ||
| new(new[] { "--pid" }, "The pid within the trace of the process to examine. If this is a multi-process trace, at least one of --pid or --process-name must be specified"); | ||
| public Option<string> ProcessName { get; } = | ||
| new(new[] { "--process-name" }, "The process name within the trace of the process to examine. If this is a multi-process trace, at least one of --pid or --process-name must be specified"); | ||
| public Option<Dictionary<string, string>> Reference = | ||
| new(new[] { "--reference", "-r" }, result => Helpers.BuildPathDictionay(result.Tokens, false), true, "If a reference is not located on disk at the same location as used in the process, it may be specified with a --reference parameter. Multiple --reference parameters may be specified. The wild cards * and ? are supported by this option"); | ||
am11 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public Option<int> ClrInstanceId { get; } = | ||
| new("--clr-instance-id", "If the process contains multiple .NET runtimes, the instance ID must be specified"); | ||
| public Option<bool> Spgo { get; } = | ||
| new("--spgo", "Base profile on samples in the input. Uses last branch records if available and otherwise raw IP samples"); | ||
| public Option<int> SpgoMinSamples { get; } = | ||
| new("--spgo-min-samples", () => 50, "The minimum number of total samples a function must have before generating profile data for it with SPGO. Default: 50"); | ||
| public Option<bool> IncludeFullGraphs { get; } = | ||
| new("--include-full-graphs", "Include all blocks and edges in the written .mibc file, regardless of profile counts"); | ||
| public Option<double> ExcludeEventsBefore { get; } = | ||
| new("--exclude-events-before", () => Double.MinValue, "Exclude data from events before specified time. Time is specified as milliseconds from the start of the trace"); | ||
| public Option<double> ExcludeEventsAfter { get; } = | ||
| new("--exclude-events-after", () => Double.MaxValue, "Exclude data from events after specified time. Time is specified as milliseconds from the start of the trace"); | ||
| public Option<bool> Compressed { get; } = | ||
| new("--compressed", () => true, "Generate compressed mibc"); | ||
| public Option<int> DumpWorstOverlapGraphs { get; } = | ||
| new("--dump-worst-overlap-graphs", () => -1, "Number of graphs to dump to .dot format in dump-worst-overlap-graphs-to directory"); | ||
| public Option<string> DumpWorstOverlapGraphsTo { get; } = | ||
| new("--dump-worst-overlap-graphs-to", "Number of graphs to dump to .dot format in dump-worst-overlap-graphs-to directory"); | ||
| public Option<bool> InheritTimestamp { get; } = | ||
| new("--inherit-timestamp", "If specified, set the output's timestamp to the max timestamp of the input files"); | ||
| public Option<bool> AutomaticReferences { get; } = | ||
| new("--automatic-references", () => true, "Attempt to find references by using paths embedded in the trace file. Defaults to true"); | ||
| public Option<AssemblyName[]> IncludedAssemblies { get; } = | ||
| new("--include-reference", result => | ||
| { | ||
| if (result.Tokens.Count > 0) | ||
| { | ||
| var includedAssemblies = new List<AssemblyName>(); | ||
| foreach (Token token in result.Tokens) | ||
| { | ||
| try | ||
| { | ||
| includedAssemblies.Add(new AssemblyName(token.Value)); | ||
| } | ||
| catch | ||
| { | ||
| throw new FormatException($"Unable to parse '{token.Value}' as an Assembly Name."); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return Array.Empty<AssemblyName>(); | ||
| }, true, "If specified, include in Mibc file only references to the specified assemblies. Assemblies are specified as assembly names, not filenames. For instance, `System.Private.CoreLib` not `System.Private.CoreLib.dll`. Multiple --include-reference options may be specified."); | ||
|
|
||
| private Option<bool> _includeReadyToRun { get; } = | ||
| new("--includeReadyToRun", "Include ReadyToRun methods in the trace file"); | ||
| private Option<Verbosity> _verbosity { get; } = | ||
| new(new[] { "--verbose", "-v" }, () => Verbosity.normal, "Adjust verbosity level. Supported levels are minimal, normal, detailed, and diagnostic"); | ||
| private Option<bool> _isSorted { get; } = | ||
| new("--sorted", "Generate sorted output."); | ||
| private Option<bool> _showTimestamp { get; } = | ||
| new("--showtimestamp", "Show timestamps in output"); | ||
|
|
||
| public PgoFileType? FileType; | ||
| public bool ProcessJitEvents; | ||
| public bool DisplayProcessedEvents; | ||
| public bool ValidateOutputFile; | ||
| public bool GenerateCallGraph; | ||
| public bool VerboseWarnings; | ||
| public JitTraceOptions JitTraceOptions; | ||
| public bool Warnings; | ||
| public bool BasicProgressMessages; | ||
| public bool DetailedProgressMessages; | ||
| public bool DumpMibc; | ||
| public ParseResult Result; | ||
| public bool ProcessR2REvents; | ||
|
|
||
| private enum Verbosity | ||
| { | ||
| minimal, | ||
| normal, | ||
| detailed, | ||
| diagnostic | ||
| } | ||
|
|
||
| public PgoRootCommand(string[] args) : base(".NET PGO Tool") | ||
| { | ||
| Command createMbicCommand = new("create-mibc", "Transform a trace file into a Mibc profile data file") | ||
| { | ||
| TraceFilePath, | ||
| OutputFilePath, | ||
| Pid, | ||
| ProcessName, | ||
| Reference, | ||
| ClrInstanceId, | ||
| ExcludeEventsBefore, | ||
| ExcludeEventsAfter, | ||
| AutomaticReferences, | ||
| _verbosity, | ||
| Compressed, | ||
| PreciseDebugInfoFile, | ||
| Spgo, | ||
| SpgoMinSamples, | ||
| IncludeFullGraphs | ||
| }; | ||
|
|
||
| createMbicCommand.SetHandler(context => | ||
| { | ||
| FileType = PgoFileType.mibc; | ||
| GenerateCallGraph = true; | ||
| ProcessJitEvents = true; | ||
| ProcessR2REvents = true; | ||
| #if DEBUG | ||
| ValidateOutputFile = true; | ||
| #else | ||
| ValidateOutputFile = false; | ||
| #endif | ||
|
|
||
| TryExecuteWithContext(context, true); | ||
| }); | ||
|
|
||
| AddCommand(createMbicCommand); | ||
|
|
||
| #if DEBUG | ||
| Command createJitTraceCommand = new("create-jittrace","Transform a trace file into a jittrace runtime file") | ||
| { | ||
| TraceFilePath, | ||
| OutputFilePath, | ||
| Pid, | ||
| ProcessName, | ||
| Reference, | ||
| ClrInstanceId, | ||
| ExcludeEventsBefore, | ||
| ExcludeEventsAfter, | ||
| AutomaticReferences, | ||
| _verbosity, | ||
| _isSorted, | ||
| _showTimestamp, | ||
| _includeReadyToRun | ||
| }; | ||
|
|
||
| createJitTraceCommand.SetHandler(context => | ||
| { | ||
| FileType = PgoFileType.jittrace; | ||
| ProcessJitEvents = true; | ||
| ValidateOutputFile = false; | ||
| ProcessR2REvents = context.ParseResult.GetValueForOption(_includeReadyToRun); | ||
|
|
||
| if (context.ParseResult.GetValueForOption(_isSorted)) | ||
| { | ||
| JitTraceOptions |= JitTraceOptions.sorted; | ||
| } | ||
|
|
||
| if (context.ParseResult.GetValueForOption(_showTimestamp)) | ||
| { | ||
| JitTraceOptions |= JitTraceOptions.showtimestamp; | ||
| } | ||
|
|
||
| TryExecuteWithContext(context, true); | ||
| }); | ||
|
|
||
| AddCommand(createJitTraceCommand); | ||
| #endif | ||
|
|
||
| Command mergeCommand = new("merge", "Merge multiple Mibc profile data files into one file") | ||
| { | ||
| InputFilesToMerge, | ||
| OutputFilePath, | ||
| IncludedAssemblies, | ||
| InheritTimestamp, | ||
| _verbosity, | ||
| Compressed | ||
| }; | ||
|
|
||
| mergeCommand.SetHandler(context => | ||
| { | ||
| #if DEBUG | ||
| ValidateOutputFile = true; | ||
| #else | ||
| ValidateOutputFile = false; | ||
| #endif | ||
|
|
||
| TryExecuteWithContext(context, true); | ||
| }); | ||
|
|
||
| AddCommand(mergeCommand); | ||
|
|
||
| Command dumpCommand = new("dump", "Dump the contents of a Mibc file") | ||
| { | ||
| _verbosity, | ||
| InputFileToDump, | ||
| OutputFilePath, | ||
| }; | ||
|
|
||
| dumpCommand.SetHandler(context => TryExecuteWithContext(context, true)); | ||
|
|
||
| AddCommand(dumpCommand); | ||
|
|
||
| Command compareMbicCommand = new Command("compare-mibc", "Compare two .mibc files") | ||
| { | ||
| InputFilesToCompare, | ||
| DumpWorstOverlapGraphs, | ||
| DumpWorstOverlapGraphsTo | ||
| }; | ||
|
|
||
| compareMbicCommand.SetHandler(context => | ||
| { | ||
| DumpMibc = true; | ||
| TryExecuteWithContext(context, false); | ||
| }); | ||
|
|
||
| AddCommand(compareMbicCommand); | ||
|
|
||
| void TryExecuteWithContext(InvocationContext context, bool setVerbosity) | ||
| { | ||
| Result = context.ParseResult; | ||
|
|
||
| if (setVerbosity) | ||
| { | ||
| Verbosity verbosity = context.ParseResult.GetValueForOption(_verbosity); | ||
| BasicProgressMessages = (int)verbosity >= (int)Verbosity.normal; | ||
| Warnings = (int)verbosity >= (int)Verbosity.normal; | ||
| VerboseWarnings = (int)verbosity >= (int)Verbosity.detailed; | ||
| DetailedProgressMessages = (int)verbosity >= (int)Verbosity.detailed; | ||
| DisplayProcessedEvents = (int)verbosity >= (int)Verbosity.diagnostic; | ||
| } | ||
|
|
||
| try | ||
| { | ||
| context.ExitCode = new Program(this).Run(); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| Console.ResetColor(); | ||
| Console.ForegroundColor = ConsoleColor.Red; | ||
|
|
||
| Console.Error.WriteLine("Error: " + e.Message); | ||
| Console.Error.WriteLine(e.ToString()); | ||
|
|
||
| Console.ResetColor(); | ||
|
|
||
| context.ExitCode = 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static IEnumerable<HelpSectionDelegate> GetExtendedHelp(HelpContext context) | ||
| { | ||
| foreach (HelpSectionDelegate sectionDelegate in HelpBuilder.Default.GetLayout()) | ||
| yield return sectionDelegate; | ||
|
|
||
| if (context.Command.Name == "create-mibc" || context.Command.Name == "create-jittrace") | ||
| { | ||
| yield return _ => | ||
| { | ||
| Console.WriteLine( | ||
| @"Example tracing commands used to generate the input to this tool: | ||
| ""dotnet-trace collect -p 73060 --providers Microsoft-Windows-DotNETRuntime:0x1E000080018:4"" | ||
| - Capture events from process 73060 where we capture both JIT and R2R events using EventPipe tracing | ||
|
|
||
| ""dotnet-trace collect -p 73060 --providers Microsoft-Windows-DotNETRuntime:0x1C000080018:4"" | ||
| - Capture events from process 73060 where we capture only JIT events using EventPipe tracing | ||
|
|
||
| ""perfview collect -LogFile:logOfCollection.txt -DataFile:jittrace.etl -Zip:false -merge:false -providers:Microsoft-Windows-DotNETRuntime:0x1E000080018:4"" | ||
| - Capture Jit and R2R events via perfview of all processes running using ETW tracing | ||
| "); | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.