Skip to content

Commit 40c5905

Browse files
committed
[DotnetTrace][CollectLinux] Add ProgressStatus and output file to tests
1 parent 208086f commit 40c5905

File tree

2 files changed

+144
-110
lines changed

2 files changed

+144
-110
lines changed

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

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,6 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
135135
scriptPath = null;
136136
List<string> recordTraceArgs = new();
137137

138-
string resolvedOutput = ResolveOutputPath(args.Output);
139-
recordTraceArgs.Add($"--out");
140-
recordTraceArgs.Add(resolvedOutput);
141-
142138
string[] profiles = args.Profiles;
143139
if (args.Profiles.Length == 0 && args.Providers.Length == 0 && string.IsNullOrEmpty(args.ClrEvents) && args.PerfEvents.Length == 0)
144140
{
@@ -169,17 +165,18 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
169165
scriptBuilder.Append($"record_dotnet_provider(\"{providerName}\", 0x{keywords:X}, {eventLevel}, {providerNameSanitized}_flags);\n\n");
170166
}
171167

172-
Console.WriteLine($"{("Linux Events"),-80}Enabled By");
168+
List<string> linuxEventLines = new();
173169
foreach (string profile in profiles)
174170
{
175171
Profile traceProfile = ListProfilesCommandHandler.TraceProfiles
176172
.FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
177173

178-
if (!string.IsNullOrEmpty(traceProfile.VerbExclusivity) &&
174+
if (traceProfile != null &&
175+
!string.IsNullOrEmpty(traceProfile.VerbExclusivity) &&
179176
traceProfile.VerbExclusivity.Equals("collect-linux", StringComparison.OrdinalIgnoreCase))
180177
{
181178
recordTraceArgs.Add(traceProfile.CollectLinuxArgs);
182-
Console.WriteLine($"{traceProfile.Name,-80}--profile");
179+
linuxEventLines.Add($"{traceProfile.Name,-80}--profile");
183180
}
184181
}
185182

@@ -193,14 +190,32 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
193190

194191
string perfProvider = split[0];
195192
string perfEventName = split[1];
196-
Console.WriteLine($"{perfEvent,-80}--perf-events");
193+
linuxEventLines.Add($"{perfEvent,-80}--perf-events");
197194
scriptBuilder.Append($"let {perfEventName} = event_from_tracefs(\"{perfProvider}\", \"{perfEventName}\");\nrecord_event({perfEventName});\n\n");
198195
}
196+
197+
if (linuxEventLines.Count > 0)
198+
{
199+
Console.WriteLine($"{("Linux Perf Events"),-80}Enabled By");
200+
foreach (string line in linuxEventLines)
201+
{
202+
Console.WriteLine(line);
203+
}
204+
}
205+
else
206+
{
207+
Console.WriteLine("No Linux Perf Events enabled.");
208+
}
209+
Console.WriteLine();
210+
211+
FileInfo resolvedOutput = ResolveOutputPath(args.Output);
212+
recordTraceArgs.Add($"--out");
213+
recordTraceArgs.Add(resolvedOutput.FullName);
214+
Console.WriteLine($"Output File : {resolvedOutput.FullName}");
199215
Console.WriteLine();
200216

201217
string scriptText = scriptBuilder.ToString();
202-
string scriptFileName = $"{Path.GetFileNameWithoutExtension(resolvedOutput)}.script";
203-
scriptPath = Path.Combine(Environment.CurrentDirectory, scriptFileName);
218+
scriptPath = Path.ChangeExtension(resolvedOutput.FullName, ".script");
204219
File.WriteAllText(scriptPath, scriptText);
205220

206221
recordTraceArgs.Add("--script-file");
@@ -210,15 +225,15 @@ private byte[] BuildRecordTraceArgs(CollectLinuxArgs args, out string scriptPath
210225
return Encoding.UTF8.GetBytes(options);
211226
}
212227

213-
private static string ResolveOutputPath(FileInfo output)
228+
private static FileInfo ResolveOutputPath(FileInfo output)
214229
{
215230
if (!string.Equals(output.Name, CommonOptions.DefaultTraceName, StringComparison.OrdinalIgnoreCase))
216231
{
217-
return output.Name;
232+
return output;
218233
}
219234

220235
DateTime now = DateTime.Now;
221-
return $"trace_{now:yyyyMMdd}_{now:HHmmss}.nettrace";
236+
return new FileInfo($"trace_{now:yyyyMMdd}_{now:HHmmss}.nettrace");
222237
}
223238

224239
private int OutputHandler(uint type, IntPtr data, UIntPtr dataLen)

src/tests/dotnet-trace/CollectLinuxCommandFunctionalTests.cs

Lines changed: 116 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private static CollectLinuxCommandHandler.CollectLinuxArgs TestArgs(
3434
clrEvents,
3535
perfEvents ?? Array.Empty<string>(),
3636
profile ?? Array.Empty<string>(),
37-
output ?? new FileInfo(CommonOptions.DefaultTraceName),
37+
output ?? new FileInfo("trace.nettrace"),
3838
duration);
3939
}
4040

@@ -47,7 +47,7 @@ public void CollectLinuxCommandProviderConfigurationConsolidation(object testArg
4747
if (OperatingSystem.IsLinux())
4848
{
4949
Assert.Equal((int)ReturnCode.Ok, exitCode);
50-
console.AssertSanitizedLinesEqual(null, expectedLines: expectedLines);
50+
console.AssertSanitizedLinesEqual(CollectLinuxSanitizer, expectedLines: expectedLines);
5151
}
5252
else
5353
{
@@ -81,138 +81,114 @@ public void CollectLinuxCommandProviderConfigurationConsolidation_Throws(object
8181
private static int Run(object args, MockConsole console)
8282
{
8383
var handler = new CollectLinuxCommandHandler(console);
84-
handler.RecordTraceInvoker = (cmd, len, cb) => 0;
84+
handler.RecordTraceInvoker = (cmd, len, cb) => {
85+
cb(3, IntPtr.Zero, UIntPtr.Zero);
86+
return 0;
87+
};
8588
return handler.CollectLinux((CollectLinuxCommandHandler.CollectLinuxArgs)args);
8689
}
8790

91+
private static string[] CollectLinuxSanitizer(string[] lines)
92+
{
93+
List<string> result = new();
94+
foreach (string line in lines)
95+
{
96+
if (line.Contains("Recording trace.", StringComparison.OrdinalIgnoreCase))
97+
{
98+
result.Add("[dd:hh:mm:ss]\tRecording trace.");
99+
}
100+
else
101+
{
102+
result.Add(line);
103+
}
104+
}
105+
return result.ToArray();
106+
}
88107

89108
public static IEnumerable<object[]> BasicCases()
90109
{
91110
yield return new object[] {
92111
TestArgs(),
93-
new string[] {
94-
"No providers, profiles, ClrEvents, or PerfEvents were specified, defaulting to trace profiles 'dotnet-common' + 'cpu-sampling'.",
95-
"",
96-
ProviderHeader,
97-
FormatProvider("Microsoft-Windows-DotNETRuntime","000000100003801D","Informational",4,"--profile"),
98-
"",
99-
LinuxHeader,
100-
LinuxProfile("cpu-sampling"),
101-
""
102-
}
112+
ExpectProvidersAndLinuxWithMessages(
113+
new[]{"No providers, profiles, ClrEvents, or PerfEvents were specified, defaulting to trace profiles 'dotnet-common' + 'cpu-sampling'."},
114+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","000000100003801D","Informational",4,"--profile")},
115+
new[]{LinuxProfile("cpu-sampling")})
103116
};
117+
104118
yield return new object[] {
105119
TestArgs(providers: new[]{"Foo:0x1:4"}),
106-
new string[] {
107-
"",
108-
ProviderHeader,
109-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
110-
"",
111-
LinuxHeader,
112-
""
113-
}
120+
ExpectProvidersAndLinux(
121+
new[]{FormatProvider("Foo","0000000000000001","Informational",4,"--providers")},
122+
Array.Empty<string>())
114123
};
124+
115125
yield return new object[] {
116126
TestArgs(providers: new[]{"Foo:0x1:4","Bar:0x2:4"}),
117-
new string[] {
118-
"",
119-
ProviderHeader,
120-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
121-
FormatProvider("Bar","0000000000000002","Informational",4,"--providers"),
122-
"",
123-
LinuxHeader,
124-
""
125-
}
127+
ExpectProvidersAndLinux(
128+
new[]{
129+
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
130+
FormatProvider("Bar","0000000000000002","Informational",4,"--providers")
131+
},
132+
Array.Empty<string>())
126133
};
134+
127135
yield return new object[] {
128136
TestArgs(profile: new[]{"cpu-sampling"}),
129-
new string[] {
130-
"No .NET providers were configured.",
131-
"",
132-
LinuxHeader,
133-
LinuxProfile("cpu-sampling"),
134-
""
135-
}
137+
ExpectProvidersAndLinuxWithMessages(
138+
new[]{"No .NET providers were configured."},
139+
Array.Empty<string>(),
140+
new[]{LinuxProfile("cpu-sampling")})
136141
};
142+
137143
yield return new object[] {
138144
TestArgs(providers: new[]{"Foo:0x1:4"}, profile: new[]{"cpu-sampling"}),
139-
new string[] {
140-
"",
141-
ProviderHeader,
142-
FormatProvider("Foo","0000000000000001","Informational",4,"--providers"),
143-
"",
144-
LinuxHeader,
145-
LinuxProfile("cpu-sampling"),
146-
""
147-
}
145+
ExpectProvidersAndLinux(
146+
new[]{FormatProvider("Foo","0000000000000001","Informational",4,"--providers")},
147+
new[]{LinuxProfile("cpu-sampling")})
148148
};
149+
149150
yield return new object[] {
150151
TestArgs(clrEvents: "gc", profile: new[]{"cpu-sampling"}),
151-
new string[] {
152-
"",
153-
ProviderHeader,
154-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--clrevents"),
155-
"",
156-
LinuxHeader,
157-
LinuxProfile("cpu-sampling"),
158-
""
159-
}
152+
ExpectProvidersAndLinux(
153+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--clrevents")},
154+
new[]{LinuxProfile("cpu-sampling")})
160155
};
156+
161157
yield return new object[] {
162158
TestArgs(providers: new[]{"Microsoft-Windows-DotNETRuntime:0x1:4"}, profile: new[]{"cpu-sampling"}),
163-
new string[] {
164-
"",
165-
ProviderHeader,
166-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers"),
167-
"",
168-
LinuxHeader,
169-
LinuxProfile("cpu-sampling"),
170-
""
171-
}
159+
ExpectProvidersAndLinux(
160+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers")},
161+
new[]{LinuxProfile("cpu-sampling")})
172162
};
163+
173164
yield return new object[] {
174165
TestArgs(providers: new[]{"Microsoft-Windows-DotNETRuntime:0x1:4"}, clrEvents: "gc"),
175-
new string[] {
176-
"Warning: The CLR provider was already specified through --providers or --profile. Ignoring --clrevents.",
177-
"",
178-
ProviderHeader,
179-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers"),
180-
"",
181-
LinuxHeader,
182-
""
183-
}
166+
ExpectProvidersAndLinuxWithMessages(
167+
new[]{"Warning: The CLR provider was already specified through --providers or --profile. Ignoring --clrevents."},
168+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000001","Informational",4,"--providers")},
169+
Array.Empty<string>())
184170
};
171+
185172
yield return new object[] {
186173
TestArgs(clrEvents: "gc+jit"),
187-
new string[] {
188-
"",
189-
ProviderHeader,
190-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Informational",4,"--clrevents"),
191-
"",
192-
LinuxHeader,
193-
""
194-
}
174+
ExpectProvidersAndLinux(
175+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Informational",4,"--clrevents")},
176+
Array.Empty<string>())
195177
};
178+
196179
yield return new object[] {
197180
TestArgs(clrEvents: "gc+jit", clrEventLevel: "5"),
198-
new string[] {
199-
"",
200-
ProviderHeader,
201-
FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Verbose",5,"--clrevents"),
202-
"",
203-
LinuxHeader,
204-
""
205-
}
181+
ExpectProvidersAndLinux(
182+
new[]{FormatProvider("Microsoft-Windows-DotNETRuntime","0000000000000011","Verbose",5,"--clrevents")},
183+
Array.Empty<string>())
206184
};
185+
207186
yield return new object[] {
208187
TestArgs(perfEvents: new[]{"sched:sched_switch"}),
209-
new string[] {
210-
"No .NET providers were configured.",
211-
"",
212-
LinuxHeader,
213-
LinuxPerfEvent("sched:sched_switch"),
214-
""
215-
}
188+
ExpectProvidersAndLinuxWithMessages(
189+
new[]{"No .NET providers were configured."},
190+
Array.Empty<string>(),
191+
new[]{LinuxPerfEvent("sched:sched_switch")})
216192
};
217193
}
218194

@@ -250,7 +226,7 @@ public static IEnumerable<object[]> InvalidProviders()
250226
}
251227

252228
private const string ProviderHeader = "Provider Name Keywords Level Enabled By";
253-
private static string LinuxHeader => $"{"Linux Events",-80}Enabled By";
229+
private static string LinuxHeader => $"{"Linux Perf Events",-80}Enabled By";
254230
private static string LinuxProfile(string name) => $"{name,-80}--profile";
255231
private static string LinuxPerfEvent(string spec) => $"{spec,-80}--perf-events";
256232
private static string FormatProvider(string name, string keywordsHex, string levelName, int levelValue, string enabledBy)
@@ -261,5 +237,48 @@ private static string FormatProvider(string name, string keywordsHex, string lev
261237
return string.Format("{0, -80}", display) + enabledBy;
262238
}
263239
private static string FormatException(string message, string exceptionType) => $"[ERROR] {exceptionType}: {message}";
240+
private static string DefaultOutputFile => $"Output File : {Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar}trace.nettrace";
241+
private static readonly string[] CommonTail = [
242+
DefaultOutputFile,
243+
"",
244+
"[dd:hh:mm:ss]\tRecording trace.",
245+
"Press <Enter> or <Ctrl-C> to exit...",
246+
];
247+
248+
private static string[] ExpectProvidersAndLinux(string[] dotnetProviders, string[] linuxPerfEvents)
249+
=> ExpectProvidersAndLinuxWithMessages(Array.Empty<string>(), dotnetProviders, linuxPerfEvents);
250+
251+
private static string[] ExpectProvidersAndLinuxWithMessages(string[] messages, string[] dotnetProviders, string[] linuxPerfEvents)
252+
{
253+
List<string> result = new();
254+
255+
if (messages.Length > 0)
256+
{
257+
result.AddRange(messages);
258+
}
259+
result.Add("");
260+
261+
if (dotnetProviders.Length > 0)
262+
{
263+
result.Add(ProviderHeader);
264+
result.AddRange(dotnetProviders);
265+
result.Add("");
266+
}
267+
268+
if (linuxPerfEvents.Length > 0)
269+
{
270+
result.Add(LinuxHeader);
271+
result.AddRange(linuxPerfEvents);
272+
}
273+
else
274+
{
275+
result.Add("No Linux Perf Events enabled.");
276+
}
277+
result.Add("");
278+
279+
result.AddRange(CommonTail);
280+
281+
return result.ToArray();
282+
}
264283
}
265284
}

0 commit comments

Comments
 (0)