Recording trace 38MB
's' - stop tracing
- 'g' - capture GC heap snapshot
...Hit 's'...
SYNOPSIS
- dotnet-trace [--version]
- [-h, --help]
- <command> [<args>]
+ dotnet-trace [options] [command] [<args>]
OPTIONS
COMMANDS
- collect Collects a diagnostic trace from a currently running process
- convert Converts traces to alternate formats for use with alternate trace analysis tools
- pack Compresses a trace and any necessary symbols into a single zip file for easy off-machine analysis
+ collect Collects a diagnostic trace from a currently running process
+ list-processes Lists dotnet processes that can be attached to.
+ list-profiles Lists pre-built tracing profiles with a description of what providers and filters are in each profile.
+ convert Converts traces to alternate formats for use with alternate trace analysis tools
COLLECT
dotnet-trace collect -p|--process-id <pid>
[-h|--help]
[-o|--output <trace-file-path>]
- [--pack]
[--profile <profile_name>]
[--providers <list-of-comma-separated-providers>]
[-f|--format <trace-file-format>]
-o, --output
The output path for the collected trace data. If not specified it defaults to ./trace.netperf
- --pack
- Automatically runs the pack command after collection is complete. Use dotnet-trace pack --help for more
- details.
-
--profile
A named pre-defined set of provider configurations that allows common tracing scenarios to be specified
succinctly. The options are:
runtime-basic Useful for tracking CPU usage and general runtime information. This the default option
if no profile is specified.
- asp-net-basic Useful starting point for ASP.Net performance investigations
gc Tracks allocation and collection performance
gc-collect Tracks GC collection only at very low overhead
none Tracks nothing. Only providers specified by the --providers option will be available.
Examples:
- > dotnet trace collect --process-id 1902 --pack
+ > dotnet trace collect --process-id 1902
Recording trace 38MB
's' - stop tracing
- 'g' - capture GC heap snapshot
-
- <Process exits>
-
- > dotnet trace collect --process-id 1902 --pack
- Recording trace 107MB
- Recording complete (process exited)
- Packing...
- Trace complete: ~/trace.netperf.zip
CONVERT
Writing: ./trace.speedscope.json
Conversion complete
-PACK
-
- dotnet-trace pack [-h|--help]
- [-o|--output <output_file_path>]
- [--verbose]
- <trace_file_path>
-
- Compresses a trace and any necessary symbols into a single zip file for easy off-machine analysis
-
- -h, --help
- Show command line help
-
- -o, --output
- The path where the pack is written. If unspecified the pack is written in the current directory
- using the same base filename as the input file and the .zip extension.
-
- --verbose
- Logs detailed information about what the pack command is doing.
-
- trace_file_path
- The path to the trace file that should be packed.
-
-
- Examples:
- > dotnet-trace pack trace.netperf
- Packing: ./trace.netperf.zip
- Pack complete
-
- > dotnet-trace pack --verbose trace.netperf
- Packing: /usr/home/noahfalk/trace.netperf.zip
- Compressing /usr/home/noahfalk/trace.netperf
- Checking /usr/bin/dotnet/shared/3.0.170/System.Private.CoreLib.dll
- Not packing symbols - Policy skips Microsoft binary
- Checking /usr/bin/dotnet/shared/3.0.170/System.Diagnostics.dll
- Not packing symbols - Policy skips Microsoft binary
- Checking /usr/home/noahfalk/MyApp/Newtonsoft.Json.dll
- Searching for Newtonsoft.Json.pdb
- Searching /usr/home/noahfalk/MyApp/Newtonsoft.Json.pdb
- Not packing symbols - Newtonsoft.Json.pdb not found
- Checking /usr/home/noahfalk/MyApp/MyApp.dll
- Searching for MyApp.pdb
- Searching /usr/home/noahfalk/MyApp/MyApp.pdb
- Found matching symbol file
- Compressing symbol file /usr/home/noahfalk/MyApp/MyApp.pdb
- ...
- Pack Complete
-
### dotnet-dump
SYNOPSIS
### dotnet-trace
+- Capture GC heap snapshot
+
+Add a command to `dotnet-trace collect` that enables the collection of GC heap snapshots on an active tracing session.
+
+- Compress a trace and any necessary symbols into a single zip file for easy off-machine analysis
+
+ OPTION
+
+ [--pack] Automatically runs the pack command after collection is complete. Use dotnet-trace pack --help for more details.
+
+ USAGE
+
+ > dotnet trace collect --process-id 1902 --pack
+ Recording trace 107MB
+ Recording complete (process exited)
+ Packing...
+ Trace complete: ~/trace.netperf.zip
+
+ VERB
+
+ pack Compresses a trace and any necessary symbols into a single zip file for easy off-machine analysis
+
+ PACK
+
+ dotnet-trace pack [-h|--help]
+ [-o|--output <output_file_path>]
+ [--verbose]
+ <trace_file_path>
+
+ Compresses a trace and any necessary symbols into a single zip file for easy off-machine analysis
+
+ -h, --help
+ Show command line help
+
+ -o, --output
+ The path where the pack is written. If unspecified the pack is written in the current directory
+ using the same base filename as the input file and the .zip extension.
+
+ --verbose
+ Logs detailed information about what the pack command is doing.
+
+ trace_file_path
+ The path to the trace file that should be packed.
+
+
+ Examples:
+ > dotnet-trace pack trace.netperf
+ Packing: ./trace.netperf.zip
+ Pack complete
+
+ > dotnet-trace pack --verbose trace.netperf
+ Packing: /usr/home/noahfalk/trace.netperf.zip
+ Compressing /usr/home/noahfalk/trace.netperf
+ Checking /usr/bin/dotnet/shared/3.0.170/System.Private.CoreLib.dll
+ Not packing symbols - Policy skips Microsoft binary
+ Checking /usr/bin/dotnet/shared/3.0.170/System.Diagnostics.dll
+ Not packing symbols - Policy skips Microsoft binary
+ Checking /usr/home/noahfalk/MyApp/Newtonsoft.Json.dll
+ Searching for Newtonsoft.Json.pdb
+ Searching /usr/home/noahfalk/MyApp/Newtonsoft.Json.pdb
+ Not packing symbols - Newtonsoft.Json.pdb not found
+ Checking /usr/home/noahfalk/MyApp/MyApp.dll
+ Searching for MyApp.pdb
+ Searching /usr/home/noahfalk/MyApp/MyApp.pdb
+ Found matching symbol file
+ Compressing symbol file /usr/home/noahfalk/MyApp/MyApp.pdb
+ ...
+ Pack Complete
+
- Multi-process collection
Make the --process-id argument optional or let it take a list of ids to create multi-process traces
### dotnet-trace
+- Add a useful starting point profile for ASP.NET performance investigations
+
- Does dotnet-trace support other tracing systems or EventPipe only?
EventPipe only, at least for now. Trying to be a front-end for various other tracing systems (etw, perf, lttng) comes with a substantial increase in complexity and other tools are already doing that such as PerfView and perfcollect. Although creating a unified front-end might have a little value, it is lower priority than doing a good job at our key goal - providing a platform agnostic solution for managed CPU and memory investigations.
if (profile == null)
throw new ArgumentNullException(nameof(profile));
- var selectedProfile = ProfilesCommandHandler.DotNETRuntimeProfiles
+ var selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
.FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
if (selectedProfile == null)
throw new ArgumentException($"Invalid profile name: {profile}");
private static Option CircularBufferOption() =>
new Option(
alias: "--buffersize",
- description: $"Sets the size of the in-memory circular buffer in megabytes. Default {DefaultCircularBufferSizeInMB} MB",
+ description: $"Sets the size of the in-memory circular buffer in megabytes. Default {DefaultCircularBufferSizeInMB} MB.",
argument: new Argument<uint>(defaultValue: DefaultCircularBufferSizeInMB) { Name = "size" },
isHidden: false);
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Tools.RuntimeClient;
-using System;
-using System.CommandLine;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace Microsoft.Diagnostics.Tools.Trace
-{
- internal static class EndPointsCommandHandler
- {
- public static async Task<int> GetActivePorts(IConsole console)
- {
- try
- {
- var processes = EventPipeClient.ListAvailablePorts()
- .Select(GetProcessById)
- .Where(process => process != null)
- .OrderBy(process => process.ProcessName)
- .ThenBy(process => process.Id);
-
- foreach (var process in processes)
- Console.Out.WriteLine($"{process.Id, 10} {process.ProcessName, -10} {process.MainModule.FileName}");
-
- await Task.FromResult(0);
- return 0;
- }
- catch (Exception ex)
- {
- Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
- return 1;
- }
- }
-
- private static Process GetProcessById(int processId)
- {
- try
- {
- return Process.GetProcessById(processId);
- }
- catch (ArgumentException)
- {
- return null;
- }
- }
-
- public static Command ActivePortsCommand() =>
- new Command(
- name: "endpoints",
- description: "List all active DotNet Core Diagnostic endpoints.",
- handler: System.CommandLine.Invocation.CommandHandler.Create<IConsole>(GetActivePorts),
- isHidden: false);
- }
-}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using System;
+using System.CommandLine;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostics.Tools.Trace
+{
+ internal static class ListProcessesCommandHandler
+ {
+ public static async Task<int> GetActivePorts(IConsole console)
+ {
+ try
+ {
+ var processes = EventPipeClient.ListAvailablePorts()
+ .Select(GetProcessById)
+ .Where(process => process != null)
+ .OrderBy(process => process.ProcessName)
+ .ThenBy(process => process.Id);
+
+ foreach (var process in processes)
+ Console.Out.WriteLine($"{process.Id, 10} {process.ProcessName, -10} {process.MainModule.FileName}");
+
+ await Task.FromResult(0);
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
+ return 1;
+ }
+ }
+
+ private static Process GetProcessById(int processId)
+ {
+ try
+ {
+ return Process.GetProcessById(processId);
+ }
+ catch (ArgumentException)
+ {
+ return null;
+ }
+ }
+
+ public static Command ListProcessesCommand() =>
+ new Command(
+ name: "list-processes",
+ description: "Lists dotnet processes that can be attached to.",
+ handler: System.CommandLine.Invocation.CommandHandler.Create<IConsole>(GetActivePorts),
+ isHidden: false);
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Microsoft.Diagnostics.Tracing.Parsers;
+using System;
+using System.Collections.Generic;
+using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.Diagnostics.Tracing;
+using System.Threading.Tasks;
+
+namespace Microsoft.Diagnostics.Tools.Trace
+{
+ internal sealed class ListProfilesCommandHandler
+ {
+ public static async Task<int> GetProfiles(IConsole console)
+ {
+ try
+ {
+ foreach (var profile in DotNETRuntimeProfiles)
+ Console.Out.WriteLine($"\t{profile.Name,-16} - {profile.Description}");
+
+ await Task.FromResult(0);
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
+ return 1;
+ }
+ }
+
+ public static Command ListProfilesCommand() =>
+ new Command(
+ name: "list-profiles",
+ description: "Lists pre-built tracing profiles with a description of what providers and filters are in each profile.",
+ handler: CommandHandler.Create<IConsole>(GetProfiles),
+ isHidden: false);
+
+ // FIXME: Read from a config file!
+ internal static IEnumerable<Profile> DotNETRuntimeProfiles { get; } = new[] {
+ new Profile(
+ "runtime-basic",
+ new Provider[] {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ new Provider("Microsoft-Windows-DotNETRuntime", (ulong)ClrTraceEventParser.Keywords.Default, EventLevel.Informational),
+ },
+ "Useful for tracking CPU usage and general runtime information. This the default option if no profile is specified."),
+#if DEBUG // Coming soon: Preview6
+ new Profile(
+ "gc",
+ new Provider[] {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ new Provider(
+ name: "Microsoft-Windows-DotNETRuntime",
+ keywords: (ulong)ClrTraceEventParser.Keywords.GC |
+ (ulong)ClrTraceEventParser.Keywords.GCHeapSurvivalAndMovement |
+ (ulong)ClrTraceEventParser.Keywords.Stack |
+ (ulong)ClrTraceEventParser.Keywords.Jit |
+ (ulong)ClrTraceEventParser.Keywords.StopEnumeration |
+ (ulong)ClrTraceEventParser.Keywords.SupressNGen |
+ (ulong)ClrTraceEventParser.Keywords.Loader |
+ (ulong)ClrTraceEventParser.Keywords.Exception,
+ eventLevel: EventLevel.Verbose),
+ },
+ "Tracks allocation and collection performance."),
+ new Profile(
+ "gc-collect",
+ new Provider[] {
+ new Provider("Microsoft-DotNETCore-SampleProfiler"),
+ new Provider(
+ name: "Microsoft-Windows-DotNETRuntime",
+ keywords: (ulong)ClrTraceEventParser.Keywords.GC |
+ (ulong)ClrTraceEventParser.Keywords.Exception,
+ eventLevel: EventLevel.Informational),
+ },
+ "Tracks GC collection only at very low overhead."),
+#endif // DEBUG
+ new Profile(
+ "none",
+ null,
+ "Tracks nothing. Only providers specified by the --providers option will be available."),
+ };
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Diagnostics.Tools.RuntimeClient;
-using Microsoft.Diagnostics.Tracing.Parsers;
-using System;
-using System.Collections.Generic;
-using System.CommandLine;
-using System.CommandLine.Invocation;
-using System.Diagnostics.Tracing;
-using System.Threading.Tasks;
-
-namespace Microsoft.Diagnostics.Tools.Trace
-{
- internal sealed class ProfilesCommandHandler
- {
- public static async Task<int> GetProfiles(IConsole console)
- {
- try
- {
- foreach (var profile in DotNETRuntimeProfiles)
- Console.Out.WriteLine($"\t{profile.Name,-16} - {profile.Description}");
-
- await Task.FromResult(0);
- return 0;
- }
- catch (Exception ex)
- {
- Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
- return 1;
- }
- }
-
- public static Command ProfilesCommand() =>
- new Command(
- name: "profiles",
- description: "List pre-defined set of provider aliases that allows common tracing scenarios to be specified.",
- handler: CommandHandler.Create<IConsole>(GetProfiles),
- isHidden: false);
-
- // FIXME: Read from a config file!
- internal static IEnumerable<Profile> DotNETRuntimeProfiles { get; } = new[] {
- new Profile(
- "runtime-basic",
- new Provider[] {
- new Provider("Microsoft-DotNETCore-SampleProfiler"),
- new Provider("Microsoft-Windows-DotNETRuntime", (ulong)ClrTraceEventParser.Keywords.Default, EventLevel.Informational),
- },
- "Useful for tracking CPU usage and general runtime information. This the default option if no profile is specified."),
-#if DEBUG // Coming soon: Preview6
- new Profile(
- "gc",
- new Provider[] {
- new Provider("Microsoft-DotNETCore-SampleProfiler"),
- new Provider(
- name: "Microsoft-Windows-DotNETRuntime",
- keywords: (ulong)ClrTraceEventParser.Keywords.GC |
- (ulong)ClrTraceEventParser.Keywords.GCHeapSurvivalAndMovement |
- (ulong)ClrTraceEventParser.Keywords.Stack |
- (ulong)ClrTraceEventParser.Keywords.Jit |
- (ulong)ClrTraceEventParser.Keywords.StopEnumeration |
- (ulong)ClrTraceEventParser.Keywords.SupressNGen |
- (ulong)ClrTraceEventParser.Keywords.Loader |
- (ulong)ClrTraceEventParser.Keywords.Exception,
- eventLevel: EventLevel.Verbose),
- },
- "Tracks allocation and collection performance."),
- new Profile(
- "gc-collect",
- new Provider[] {
- new Provider("Microsoft-DotNETCore-SampleProfiler"),
- new Provider(
- name: "Microsoft-Windows-DotNETRuntime",
- keywords: (ulong)ClrTraceEventParser.Keywords.GC |
- (ulong)ClrTraceEventParser.Keywords.Exception,
- eventLevel: EventLevel.Informational),
- },
- "Tracks GC collection only at very low overhead."),
-#endif // DEBUG
- new Profile(
- "none",
- null,
- "Tracks nothing. Only providers specified by the --providers option will be available."),
- };
- }
-}
.AddCommand(StopCommandHandler.StopCommand())
#endif
.AddCommand(CollectCommandHandler.CollectCommand())
- .AddCommand(EndPointsCommandHandler.ActivePortsCommand())
- .AddCommand(ProfilesCommandHandler.ProfilesCommand())
+ .AddCommand(ListProcessesCommandHandler.ListProcessesCommand())
+ .AddCommand(ListProfilesCommandHandler.ListProfilesCommand())
.UseDefaults()
.Build();