diff --git a/src/TraceEvent/Parsers/ClrTraceEventParser.cs b/src/TraceEvent/Parsers/ClrTraceEventParser.cs index a905fa8bb..d49c5f3f9 100644 --- a/src/TraceEvent/Parsers/ClrTraceEventParser.cs +++ b/src/TraceEvent/Parsers/ClrTraceEventParser.cs @@ -11956,6 +11956,7 @@ public abstract class MethodLoadUnloadTraceDataBase : TraceEvent public bool IsDynamic { get { return (MethodFlags & MethodFlags.Dynamic) != 0; } } public bool IsGeneric { get { return (MethodFlags & MethodFlags.Generic) != 0; } } public bool IsJitted { get { return (MethodFlags & MethodFlags.Jitted) != 0; } } + public bool IsJitHelper { get { return (MethodFlags & MethodFlags.JitHelper) != 0; } } public OptimizationTier OptimizationTier { diff --git a/src/TraceEvent/TraceLog.cs b/src/TraceEvent/TraceLog.cs index f1036b304..0988ea73a 100644 --- a/src/TraceEvent/TraceLog.cs +++ b/src/TraceEvent/TraceLog.cs @@ -346,8 +346,8 @@ private void SetupInitialRundownCallbacks(EventPipeEventSource rawEvents) TraceProcess process = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC); process.InsertJITTEDMethod(data.MethodStartAddress, data.MethodSize, delegate () { - TraceManagedModule module = process.LoadedModules.GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC); - MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(GetFullName(data), module.ModuleFile.ModuleFileIndex, data.MethodToken); + TraceModuleFile moduleFile = process.LoadedModules.GetOrCreateMethodModuleFile(data); + MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(GetFullName(data), moduleFile.ModuleFileIndex, data.MethodToken); return new TraceProcess.MethodLookupInfo(data.MethodStartAddress, data.MethodSize, methodIndex); }); }; @@ -1363,7 +1363,7 @@ private unsafe void SetupCallbacks(TraceEventDispatcher rawEvents) eventCount = 0; // FIX NOW HACK, because Method and Module unload methods are missing. - jittedMethods = new List(); + methodLoadEvents = new List(); jsJittedMethods = new List(); sourceFilesByID = new Dictionary(); @@ -1684,17 +1684,17 @@ private unsafe void SetupCallbacks(TraceEventDispatcher rawEvents) bookKeepingEvent = true; } - if (data.IsJitted) + if (ShouldTrackMethodLoad(data.MethodFlags)) { TraceProcess process = processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC); process.InsertJITTEDMethod(data.MethodStartAddress, data.MethodSize, delegate () { - TraceManagedModule module = process.LoadedModules.GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC); - MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(TraceLog.GetFullName(data), module.ModuleFile.ModuleFileIndex, data.MethodToken); + TraceModuleFile moduleFile = process.LoadedModules.GetOrCreateMethodModuleFile(data); + MethodIndex methodIndex = CodeAddresses.Methods.NewMethod(TraceLog.GetFullName(data), moduleFile.ModuleFileIndex, data.MethodToken); return new TraceProcess.MethodLookupInfo(data.MethodStartAddress, data.MethodSize, methodIndex); }); - jittedMethods.Add((MethodLoadUnloadVerboseTraceData)data.Clone()); + methodLoadEvents.Add((MethodLoadUnloadVerboseTraceData)data.Clone()); } }; rawEvents.Clr.MethodLoadVerbose += onMethodStart; @@ -2427,9 +2427,9 @@ private unsafe void CopyRawEvents(TraceEventDispatcher rawEvents, IStreamWriter userStackKeyToInfo = null; // TODO FIX NOW hack because unloadMethod not present - foreach (var jittedMethod in jittedMethods) + foreach (var methodLoadEvent in methodLoadEvents) { - codeAddresses.AddMethod(jittedMethod); + codeAddresses.AddMethod(methodLoadEvent); } foreach (var jsJittedMethod in jsJittedMethods) @@ -3531,22 +3531,36 @@ internal void DebugWarn(bool condition, string message, TraceEvent data) } internal static string GetFullName(MethodLoadUnloadVerboseTraceData data) { - string sig = data.MethodSignature; - int parens = sig.IndexOf('('); + return GetFullName(data.MethodFlags, data.MethodNamespace, data.MethodName, data.MethodSignature); + } + + private static string GetFullName(MethodFlags methodFlags, string methodNamespace, string methodName, string methodSignature) + { + if ((methodFlags & MethodFlags.JitHelper) != 0) + { + return methodName; + } + + int parens = methodSignature.IndexOf('('); string args; if (parens >= 0) { - args = sig.Substring(parens); + args = methodSignature.Substring(parens); } else { args = ""; } - string fullName = data.MethodNamespace + "." + data.MethodName + args; + string fullName = methodNamespace + "." + methodName + args; return fullName; } + private static bool ShouldTrackMethodLoad(MethodFlags methodFlags) + { + return (methodFlags & (MethodFlags.Jitted | MethodFlags.JitHelper)) != 0; + } + internal int FindPageIndex(long timeQPC) { int pageIndex; @@ -4202,8 +4216,8 @@ int IFastSerializableVersion.MinimumReaderVersion private bool noStack; // This event should never have a stack associated with it, so skip them if we every try to attach a stack. private TraceThread thread; // cache of the TraceThread for the current event. - // TODO FIX NOW remove the jittedMethods ones. - private List jittedMethods; + // TODO FIX NOW remove the methodLoadEvents ones. + private List methodLoadEvents; private List jsJittedMethods; private Dictionary sourceFilesByID; @@ -7225,6 +7239,29 @@ internal TraceManagedModule GetOrCreateManagedModule(long managedModuleID, long } return module; } + + internal TraceModuleFile GetOrCreateMethodModuleFile(MethodLoadUnloadVerboseTraceData data) + { + if (data.IsJitHelper) + { + return GetOrCreateJitHelperModuleFile(); + } + + return GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC).ModuleFile; + } + + private TraceModuleFile GetOrCreateJitHelperModuleFile() + { + if (jitHelperModuleFile == null) + { + // Stash process-private, dynamically generated runtime helpers under an invalid file path + // so they are clearly synthetic while still displaying cleanly in stacks. + string modulePath = "[generatedruntimehelpers:processindex=" + process.ProcessIndex + "]\\generatedruntimehelpers.dll"; + jitHelperModuleFile = process.Log.ModuleFiles.GetOrCreateModuleFile(modulePath, 0); + } + + return jitHelperModuleFile; + } /// /// Finds the index and module for an a given managed module ID. If not found, new module /// should be inserted at index + 1; @@ -7411,6 +7448,7 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() private TraceProcess process; private GrowableArray modules; // Contains unmanaged modules sorted by key + private TraceModuleFile jitHelperModuleFile; #endregion } @@ -8536,7 +8574,7 @@ internal void AddMethod(MethodLoadUnloadVerboseTraceData data) MethodIndex methodIndex = Microsoft.Diagnostics.Tracing.Etlx.MethodIndex.Invalid; ILMapIndex ilMap = ILMapIndex.Invalid; ModuleFileIndex moduleFileIndex = Microsoft.Diagnostics.Tracing.Etlx.ModuleFileIndex.Invalid; - TraceManagedModule module = null; + TraceModuleFile moduleFile = null; TraceProcess process = log.Processes.GetOrCreateProcess(data.ProcessID, data.TimeStampQPC); ForAllUnresolvedCodeAddressesInRange(process, data.MethodStartAddress, data.MethodSize, true, delegate (ref CodeAddressInfo info) { @@ -8545,10 +8583,10 @@ internal void AddMethod(MethodLoadUnloadVerboseTraceData data) if (info.GetMethodIndex(this) == Microsoft.Diagnostics.Tracing.Etlx.MethodIndex.Invalid) { // Lazily create the method since many methods never have code samples in them. - if (module == null) + if (moduleFile == null) { - module = process.LoadedModules.GetOrCreateManagedModule(data.ModuleID, data.TimeStampQPC); - moduleFileIndex = module.ModuleFile.ModuleFileIndex; + moduleFile = process.LoadedModules.GetOrCreateMethodModuleFile(data); + moduleFileIndex = moduleFile.ModuleFileIndex; methodIndex = methods.NewMethod(TraceLog.GetFullName(data), moduleFileIndex, data.MethodToken); if (data.IsJitted) {