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> ExcludeEventsBeforeJittingMethod { get; } =
+ new("--exclude-events-before-jitting-method") { DefaultValueFactory = _ => string.Empty, Description = "Exclude data from events before observing a specific method getting jitted. Method is matched using a regular expression against the method name. Note that the method name is formatted the same as in PerfView which includes typed parameters." };
+ public CliOption<string> ExcludeEventsAfterJittingMethod { get; } =
+ new("--exclude-events-after-jitting-method") { DefaultValueFactory = _ => string.Empty, Description = "Exclude data from events after observing a specific method getting jitted. Method is matched using a regular expression against the method name. Note that the method name is formatted the same as in PerfView which includes typed parameters." };
+ public CliOption<string> IncludeMethods { get; } =
+ new("--include-methods") { DefaultValueFactory = _ => string.Empty, Description = "Include methods with names matching regular expression. Note that the method names are formatted the same as in PerfView which includes typed parameters." };
+ public CliOption<string> ExcludeMethods { get; } =
+ new("--exclude-methods") { DefaultValueFactory = _ => string.Empty, Description = "Exclude methods with names matching regular expression. Note that the method names are formatted the same as in PerfView which includes typed parameters." };
public CliOption<bool> Compressed { get; } =
new("--compressed") { DefaultValueFactory = _ => true, Description = "Generate compressed mibc" };
public CliOption<int> DumpWorstOverlapGraphs { get; } =
ClrInstanceId,
ExcludeEventsBefore,
ExcludeEventsAfter,
+ ExcludeEventsBeforeJittingMethod,
+ ExcludeEventsAfterJittingMethod,
+ IncludeMethods,
+ ExcludeMethods,
AutomaticReferences,
_verbosity,
Compressed,
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;
double excludeEventsBefore = Get(_command.ExcludeEventsBefore);
double excludeEventsAfter = Get(_command.ExcludeEventsAfter);
+ Regex excludeEventsBeforeJittingMethod = !string.IsNullOrEmpty(Get(_command.ExcludeEventsBeforeJittingMethod)) ? new Regex(Get(_command.ExcludeEventsBeforeJittingMethod)) : null;
+ Regex excludeEventsAfterJittingMethod = !string.IsNullOrEmpty(Get(_command.ExcludeEventsAfterJittingMethod)) ? new Regex(Get(_command.ExcludeEventsAfterJittingMethod)) : null;
+ 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;
+
+ // Find all the R2RLoad events.
if (_command.ProcessR2REvents)
{
foreach (var e in p.EventsInProcess.ByEventType<R2RGetEntryPointTraceData>())
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)
PrintWarning($"Skipped R2REntryPoint {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}");
continue;
}
+
MethodDesc method = null;
string extraWarningText = null;
bool failedDueToNonloadableModule = false;
continue;
}
- if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
+ if (e.TimeStampRelativeMSec < excludeEventsBefore)
+ {
+ continue;
+ }
+
+ if (e.TimeStampRelativeMSec > excludeEventsAfter)
+ {
+ break;
+ }
+
+ string perfviewMethodName = e.MethodNamespace + "." + e.MethodName + paramsArgs;
+ if (PassesMethodFilter(includeMethods, excludeMethods, perfviewMethodName))
+ {
methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad"));
+ }
+ }
+ }
+
+ // In case requesting events before/after jitting a method, discover the
+ // corresponding excludeEventsBefore/excludeEventsAfter in event stream based
+ // on filter criterias.
+ if (_command.ProcessJitEvents && (excludeEventsBeforeJittingMethod != null || excludeEventsAfterJittingMethod != null))
+ {
+ double firstMatchEventsBeforeJittingMethod = double.PositiveInfinity;
+ double lastMatchEventsAfterJittingMethod = double.NegativeInfinity;
+ foreach (var e in p.EventsInProcess.ByEventType<MethodJittingStartedTraceData>())
+ {
+ if (e.ClrInstanceID != clrInstanceId)
+ {
+ continue;
+ }
+
+ MethodDesc method = null;
+ bool failedDueToNonloadableModule = false;
+ try
+ {
+ method = idParser.ResolveMethodID(e.MethodID, out failedDueToNonloadableModule, false);
+ }
+ catch { }
+
+ if (method == null)
+ {
+ continue;
+ }
+
+ int parenIndex = e.MethodSignature.IndexOf('(');
+ string paramsArgs = e.MethodSignature.Substring(parenIndex);
+ string perfviewMethodName = e.MethodNamespace + "." + e.MethodName + paramsArgs;
+
+ if (e.TimeStampRelativeMSec > excludeEventsBefore && e.TimeStampRelativeMSec < firstMatchEventsBeforeJittingMethod && excludeEventsBeforeJittingMethod != null && excludeEventsBeforeJittingMethod.IsMatch(perfviewMethodName))
+ {
+ firstMatchEventsBeforeJittingMethod = e.TimeStampRelativeMSec;
+ }
+
+ if (e.TimeStampRelativeMSec < excludeEventsAfter && e.TimeStampRelativeMSec > lastMatchEventsAfterJittingMethod && excludeEventsAfterJittingMethod != null && excludeEventsAfterJittingMethod.IsMatch(perfviewMethodName))
+ {
+ lastMatchEventsAfterJittingMethod = e.TimeStampRelativeMSec;
+ }
+ }
+
+ if (firstMatchEventsBeforeJittingMethod < double.PositiveInfinity)
+ {
+ excludeEventsBefore = firstMatchEventsBeforeJittingMethod;
+ }
+
+ if (lastMatchEventsAfterJittingMethod > double.NegativeInfinity)
+ {
+ excludeEventsAfter = lastMatchEventsAfterJittingMethod;
+ }
+
+ if (excludeEventsBefore > excludeEventsAfter)
+ {
+ PrintError($"Exclude events before timestamp: \"{excludeEventsBefore}\" can't be later than exclude events after timestamp: \"{excludeEventsAfter}\"");
+ return -1;
}
}
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)
continue;
}
- if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
+ if (e.TimeStampRelativeMSec < excludeEventsBefore)
+ {
+ continue;
+ }
+
+ if (e.TimeStampRelativeMSec > excludeEventsAfter)
+ {
+ break;
+ }
+
+ string perfviewMethodName = e.MethodNamespace + "." + e.MethodName + paramsArgs;
+ if (PassesMethodFilter(includeMethods, excludeMethods, perfviewMethodName))
+ {
methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart"));
+ }
}
}
return 0;
}
+ private static bool PassesMethodFilter(Regex includeMethods, Regex excludeMethods, string methodName)
+ {
+ if (includeMethods != null || excludeMethods != null)
+ {
+ if (includeMethods != null && !includeMethods.IsMatch(methodName))
+ {
+ return false;
+ }
+
+ if (excludeMethods != null && excludeMethods.IsMatch(methodName))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private static void GenerateJittraceFile(FileInfo outputFileName, IEnumerable<ProcessedMethodData> methodsToAttemptToPrepare, JitTraceOptions jittraceOptions)
{
PrintMessage($"JitTrace options {jittraceOptions}");