Skip to content

Commit a41a04a

Browse files
committed
[DotnetTrace][CollectLinux] Build record-trace args
1 parent 92fee1f commit a41a04a

File tree

1 file changed

+94
-2
lines changed

1 file changed

+94
-2
lines changed

src/Tools/dotnet-trace/CommandLine/Commands/CollectLinuxCommand.cs

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
using System.CommandLine;
66
using System.Diagnostics;
77
using System.IO;
8+
using System.Text;
89
using System.Threading.Tasks;
10+
using Microsoft.Diagnostics.NETCore.Client;
911
using Microsoft.Internal.Common.Utils;
1012

1113
namespace Microsoft.Diagnostics.Tools.Trace
@@ -35,6 +37,12 @@ private static int CollectLinux(CollectLinuxArgs args)
3537
return (int)ReturnCode.ArgumentError;
3638
}
3739

40+
if (args.ProcessId != 0 && !string.IsNullOrEmpty(args.Name))
41+
{
42+
Console.Error.WriteLine("Only one of --process-id or --name can be specified.");
43+
return (int)ReturnCode.ArgumentError;
44+
}
45+
3846
return RunRecordTrace(args);
3947
}
4048

@@ -145,14 +153,98 @@ private static bool TryResolveRecordTracePath(out string path)
145153

146154
private static List<string> BuildRecordTraceArgs(CollectLinuxArgs args)
147155
{
148-
Console.WriteLine($"{args.ProcessId}");
149156
List<string> recordTraceArgs = new();
150157

151-
recordTraceArgs.Add("--on-cpu");
158+
foreach (string profile in args.Profiles)
159+
{
160+
if (profile.Equals("kernel-cpu", StringComparison.OrdinalIgnoreCase))
161+
{
162+
recordTraceArgs.Add("--on-cpu");
163+
}
164+
if (profile.Equals("kernel-cswitch", StringComparison.OrdinalIgnoreCase))
165+
{
166+
recordTraceArgs.Add("--off-cpu");
167+
}
168+
}
169+
170+
recordTraceArgs.Add("--script");
171+
StringBuilder scriptArg = new();
172+
173+
string[] profiles = args.Profiles;
174+
if (args.Profiles.Length == 0 && args.Providers.Length == 0 && string.IsNullOrEmpty(args.ClrEvents))
175+
{
176+
Console.WriteLine("No profile or providers specified, defaulting to trace profile 'dotnet-common'");
177+
profiles = new[] { "cpu-sampling" };
178+
}
179+
List<EventPipeProvider> providerCollection = ProviderUtils.ToProviders(args.Providers, args.ClrEvents, args.ClrEventLevel, profiles);
180+
foreach (EventPipeProvider provider in providerCollection)
181+
{
182+
Console.WriteLine($"{provider}");
183+
}
184+
// Dummy event for now, until FFI is released
185+
scriptArg.Append($"let gc_start = event_from_dotnet(\"Microsoft-Windows-DotNETRuntime\", 1, 4, 1, \"GCStart_V2\"); record_event(gc_start);");
186+
187+
foreach (string perfEvent in args.PerfEvents)
188+
{
189+
if (string.IsNullOrWhiteSpace(perfEvent) || !perfEvent.Contains(':', StringComparison.Ordinal))
190+
{
191+
throw new ArgumentException($"Invalid perf event specification '{perfEvent}'. Expected format 'provider:event'.");
192+
}
193+
194+
string[] split = perfEvent.Split(':', 2, StringSplitOptions.TrimEntries);
195+
if (split.Length != 2 || string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1]))
196+
{
197+
throw new ArgumentException($"Invalid perf event specification '{perfEvent}'. Expected format 'provider:event'.");
198+
}
199+
200+
string perfProvider = split[0];
201+
string perfEventName = split[1];
202+
scriptArg.Append($"let {perfEventName} = event_from_tracefs(\"{perfProvider}\", \"{perfEventName}\"); record_event({perfEventName});");
203+
}
204+
recordTraceArgs.Add(scriptArg.ToString());
205+
206+
int pid = args.ProcessId;
207+
if (!string.IsNullOrEmpty(args.Name))
208+
{
209+
pid = CommandUtils.FindProcessIdWithName(args.Name);
210+
}
211+
if (pid > 0)
212+
{
213+
recordTraceArgs.Add($"--pid");
214+
recordTraceArgs.Add($"{pid}");
215+
}
216+
217+
string resolvedOutput = ResolveOutputPath(args.Output, pid);
218+
recordTraceArgs.Add($"--out");
219+
recordTraceArgs.Add(resolvedOutput);
220+
221+
if (args.Duration != default(TimeSpan))
222+
{
223+
recordTraceArgs.Add($"--duration");
224+
recordTraceArgs.Add(args.Duration.ToString());
225+
}
152226

153227
return recordTraceArgs;
154228
}
155229

230+
private static string ResolveOutputPath(FileInfo output, int processId)
231+
{
232+
if (!string.Equals(output.Name, CommonOptions.DefaultTraceName, StringComparison.OrdinalIgnoreCase))
233+
{
234+
return output.Name;
235+
}
236+
237+
DateTime now = DateTime.Now;
238+
if (processId > 0)
239+
{
240+
Process process = Process.GetProcessById(processId);
241+
FileInfo processMainModuleFileInfo = new(process.MainModule.FileName);
242+
return $"{processMainModuleFileInfo.Name}_{now:yyyyMMdd}_{now:HHmmss}.nettrace";
243+
}
244+
245+
return $"collect_linux_{now:yyyyMMdd}_{now:HHmmss}.nettrace";
246+
}
247+
156248
private static readonly Option<string> PerfEventsOption =
157249
new("--perf-events")
158250
{

0 commit comments

Comments
 (0)