Skip to content

Add additional filter capabilities to dotnet-pgo tool. #89853

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
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/coreclr/tools/dotnet-pgo/PgoRootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ internal sealed class PgoRootCommand : CliRootCommand
new("--exclude-events-before") { DefaultValueFactory = _ => Double.MinValue, Description = "Exclude data from events before specified time. Time is specified as milliseconds from the start of the trace" };
public CliOption<double> ExcludeEventsAfter { get; } =
new("--exclude-events-after") { DefaultValueFactory = _ => Double.MaxValue, Description = "Exclude data from events after specified time. Time is specified as milliseconds from the start of the trace" };
public CliOption<string> ExcludeEventsBeforeMethod { get; } =
new("--exclude-events-before-method") { DefaultValueFactory = _ => string.Empty, Description = "Exclude data from events before observing a specific method. Method is matched using a regular expression" };
public CliOption<string> ExcludeEventsAfterMethod { get; } =
new("--exclude-events-after-method") { DefaultValueFactory = _ => string.Empty, Description = "Exclude data from events after observing a specific method. Method is matched using a regular expression" };
public CliOption<string> IncludeMethods { get; } =
new("--include-methods") { DefaultValueFactory = _ => string.Empty, Description = "Include methods matching regular expression" };
public CliOption<string> ExcludeMethods { get; } =
new("--exclude-methods") { DefaultValueFactory = _ => string.Empty, Description = "Exclude methods matching regular expression" };
public CliOption<bool> Compressed { get; } =
new("--compressed") { DefaultValueFactory = _ => true, Description = "Generate compressed mibc" };
public CliOption<int> DumpWorstOverlapGraphs { get; } =
Expand Down Expand Up @@ -99,6 +107,10 @@ public PgoRootCommand(string[] args) : base(".NET PGO Tool")
ClrInstanceId,
ExcludeEventsBefore,
ExcludeEventsAfter,
ExcludeEventsBeforeMethod,
ExcludeEventsAfterMethod,
IncludeMethods,
ExcludeMethods,
AutomaticReferences,
_verbosity,
Compressed,
Expand Down
127 changes: 123 additions & 4 deletions src/coreclr/tools/dotnet-pgo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using System.Text;
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

using Microsoft.Diagnostics.Tools.Pgo;
Expand Down Expand Up @@ -1343,6 +1344,11 @@ private int InnerProcessTraceFileMain()

double excludeEventsBefore = Get(_command.ExcludeEventsBefore);
double excludeEventsAfter = Get(_command.ExcludeEventsAfter);
Regex excludeEventsBeforeMethod = !string.IsNullOrEmpty(Get(_command.ExcludeEventsBeforeMethod)) ? new Regex(Get(_command.ExcludeEventsBeforeMethod)) : null;
Regex excludeEventsAfterMethod = !string.IsNullOrEmpty(Get(_command.ExcludeEventsAfterMethod)) ? new Regex(Get(_command.ExcludeEventsAfterMethod)) : null;

// Find all the R2RLoad events.
SortedDictionary<double, List<Tuple<int, MethodDesc>>> sortedR2RLoadEvents = new();
if (_command.ProcessR2REvents)
{
foreach (var e in p.EventsInProcess.ByEventType<R2RGetEntryPointTraceData>())
Expand All @@ -1351,6 +1357,7 @@ private int InnerProcessTraceFileMain()
string retArg = e.MethodSignature.Substring(0, parenIndex);
string paramsArgs = e.MethodSignature.Substring(parenIndex);
string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs;

if (e.ClrInstanceID != clrInstanceId)
{
if (!_command.Warnings)
Expand Down Expand Up @@ -1382,12 +1389,33 @@ private int InnerProcessTraceFileMain()
continue;
}

if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad"));
string methodAsString = method.ToString();
if (e.TimeStampRelativeMSec > excludeEventsBefore && excludeEventsBeforeMethod != null && excludeEventsBeforeMethod.IsMatch(methodAsString))
{
excludeEventsBefore = e.TimeStampRelativeMSec;
}

if (e.TimeStampRelativeMSec < excludeEventsAfter && excludeEventsAfterMethod != null && excludeEventsAfterMethod.IsMatch(methodAsString))
{
excludeEventsAfter = e.TimeStampRelativeMSec;
}

List<Tuple<int, MethodDesc>> r2rLoadEvents = null;
if (sortedR2RLoadEvents.TryGetValue(e.TimeStampRelativeMSec, out r2rLoadEvents))
{
r2rLoadEvents.Add(new((int)e.EventIndex, method));
}
else
{
r2rLoadEvents = new ();
r2rLoadEvents.Add(new ((int)e.EventIndex, method));
sortedR2RLoadEvents.Add(e.TimeStampRelativeMSec, r2rLoadEvents);
}
}
}

// Find all the jitStart events.
SortedDictionary<double, List<Tuple<int, MethodDesc>>> sortedJitStartEvents = new();
if (_command.ProcessJitEvents)
{
foreach (var e in p.EventsInProcess.ByEventType<MethodJittingStartedTraceData>())
Expand Down Expand Up @@ -1428,8 +1456,99 @@ private int InnerProcessTraceFileMain()
continue;
}

if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart"));
string methodAsString = method.ToString();
if (e.TimeStampRelativeMSec > excludeEventsBefore && excludeEventsBeforeMethod != null && excludeEventsBeforeMethod.IsMatch(methodAsString))
{
excludeEventsBefore = e.TimeStampRelativeMSec;
}

if (e.TimeStampRelativeMSec < excludeEventsAfter && excludeEventsAfterMethod != null && excludeEventsAfterMethod.IsMatch(methodAsString))
{
excludeEventsAfter = e.TimeStampRelativeMSec;
}

List<Tuple<int, MethodDesc>> jitStartEvents = null;
if (sortedJitStartEvents.TryGetValue(e.TimeStampRelativeMSec, out jitStartEvents))
{
jitStartEvents.Add(new((int)e.EventIndex, method));
}
else
{
jitStartEvents = new();
jitStartEvents.Add(new((int)e.EventIndex, method));
sortedJitStartEvents.Add(e.TimeStampRelativeMSec, jitStartEvents);
}
}
}

Regex includeMethods = !string.IsNullOrEmpty(Get(_command.IncludeMethods)) ? new Regex(Get(_command.IncludeMethods)) : null;
Regex excludeMethods = !string.IsNullOrEmpty(Get(_command.ExcludeMethods)) ? new Regex(Get(_command.ExcludeMethods)) : null;

if (excludeEventsBefore > excludeEventsAfter)
{
PrintError($"Exclude events before timestamp: \"{excludeEventsBefore}\" can't be later than exclude events after timestamp: \"{excludeEventsAfter}\"");
return -1;
}

// Add R2RLoad events based on include/exclude criterias.
foreach (var sortedR2RLoadEvent in sortedR2RLoadEvents)
{
double timestamp = sortedR2RLoadEvent.Key;
List<Tuple<int,MethodDesc>> r2rLoadEvents = sortedR2RLoadEvent.Value;
foreach (var r2rLoadEvent in r2rLoadEvents)
{
if (timestamp < excludeEventsBefore || timestamp > excludeEventsAfter)
{
continue;
}

if (includeMethods != null || excludeMethods != null)
{
string methodAsString = r2rLoadEvent.Item2.ToString();

if (includeMethods != null && !includeMethods.IsMatch(methodAsString))
{
continue;
}

if (excludeMethods != null && excludeMethods.IsMatch(methodAsString))
{
continue;
}
}

methodsToAttemptToPrepare.Add(r2rLoadEvent.Item1, new ProcessedMethodData(timestamp, r2rLoadEvent.Item2, "R2RLoad"));
}
}

// Add jitStart events based on include/exclude criterias.
foreach (var sortedJitStartEvent in sortedJitStartEvents)
{
double timestamp = sortedJitStartEvent.Key;
List<Tuple<int, MethodDesc>> jitStartEvents = sortedJitStartEvent.Value;
foreach (var jitStartEvent in jitStartEvents)
{
if (timestamp < excludeEventsBefore || timestamp > excludeEventsAfter)
{
continue;
}

if (includeMethods != null || excludeMethods != null)
{
string methodAsString = jitStartEvent.Item2.ToString();

if (includeMethods != null && !includeMethods.IsMatch(methodAsString))
{
continue;
}

if (excludeMethods != null && excludeMethods.IsMatch(methodAsString))
{
continue;
}
}

methodsToAttemptToPrepare.Add(jitStartEvent.Item1, new ProcessedMethodData(timestamp, jitStartEvent.Item2, "JitStart"));
}
}

Expand Down