@@ -4646,6 +4646,9 @@ public override void Open(Window parentWindow, StatusBar worker, Action doAfter
46464646 SetProcessFilter(incPat);
46474647 }
46484648
4649+ // Call the launch hook to perform any initialization needed after process selection
4650+ OnStackWindowLaunch(parentWindow, processIDs);
4651+
46494652 Viewer.StatusBar.StartWork("Looking up high importance PDBs that are locally cached", delegate
46504653 {
46514654 // TODO This is probably a hack that it is here.
@@ -4742,6 +4745,19 @@ protected internal virtual void FirstAction(StackWindow stackWindow)
47424745 {
47434746 DataFile.FirstAction(stackWindow);
47444747 }
4748+
4749+ /// <summary>
4750+ /// Called after process selection but before the stack window is fully initialized.
4751+ /// This is a good place to perform validation or show warnings based on the selected processes.
4752+ /// </summary>
4753+ /// <param name="parentWindow">The parent window for any dialogs</param>
4754+ /// <param name="processIDs">The list of selected process IDs, or null if no specific processes were selected</param>
4755+ protected internal virtual void OnStackWindowLaunch(Window parentWindow, List<int> processIDs)
4756+ {
4757+ // Check for RuntimeStart events for the selected processes and warn if missing
4758+ WarnAboutMissingTypeInfoForProcesses(parentWindow, processIDs, SourceName);
4759+ }
4760+
47454761 public override ImageSource Icon { get { return GuiApp.MainWindow.Resources["StackSourceBitmapImage"] as ImageSource; } }
47464762
47474763 // If set, we don't show the process selection dialog.
@@ -4807,6 +4823,88 @@ private static bool WarnAboutBrokenStacks(Window parentWindow, float brokenPerce
48074823 return false;
48084824 }
48094825
4826+ /// <summary>
4827+ /// Checks if RuntimeStart events exist for the selected processes and warns if missing.
4828+ /// This indicates whether the processes were started after tracing began, which is required
4829+ /// for proper type information in allocation traces.
4830+ /// </summary>
4831+ private void WarnAboutMissingTypeInfoForProcesses(Window parentWindow, List<int> processIDs, string viewName)
4832+ {
4833+ // Only check for allocation-related views
4834+ if (!SourceName.StartsWith("GC Heap Alloc Ignore Free") &&
4835+ !SourceName.StartsWith("GC Heap Net Mem") &&
4836+ !SourceName.StartsWith("Gen 2 Object Deaths"))
4837+ {
4838+ return;
4839+ }
4840+
4841+ var etlDataFile = DataFile as ETLPerfViewData;
4842+ if (etlDataFile == null)
4843+ {
4844+ return;
4845+ }
4846+
4847+ var traceLog = etlDataFile.TryGetTraceLog();
4848+ if (traceLog == null)
4849+ {
4850+ return;
4851+ }
4852+
4853+ // Check if we have RuntimeStart events for the selected processes
4854+ bool hasRuntimeStartForSelectedProcesses = false;
4855+
4856+ if (processIDs != null && processIDs.Count > 0)
4857+ {
4858+ // Get the event source to iterate through events
4859+ var source = traceLog.Events.GetSource();
4860+
4861+ // Subscribe to RuntimeStart events
4862+ source.Clr.RuntimeStart += delegate (RuntimeInformationTraceData data)
4863+ {
4864+ if (processIDs.Contains(data.ProcessID))
4865+ {
4866+ hasRuntimeStartForSelectedProcesses = true;
4867+ }
4868+ };
4869+
4870+ // Process all events to check for RuntimeStart
4871+ source.Process();
4872+ }
4873+ else
4874+ {
4875+ // If no specific processes selected, check if any RuntimeStart exists
4876+ foreach (var stats in traceLog.Stats)
4877+ {
4878+ if (stats.ProviderGuid == ClrTraceEventParser.ProviderGuid && stats.EventName == "Runtime/Start")
4879+ {
4880+ hasRuntimeStartForSelectedProcesses = true;
4881+ break;
4882+ }
4883+ }
4884+ }
4885+
4886+ // Show warning if RuntimeStart not found for selected processes
4887+ if (!hasRuntimeStartForSelectedProcesses)
4888+ {
4889+ var warning = $"""
4890+ WARNING: The '{viewName}' view may be missing type information.
4891+
4892+ This can happen when the ETW circular buffer wraps and loses early events including type definitions.
4893+ Without these type definitions, many types will appear as "UNKNOWN" in the allocation view.
4894+
4895+ To fix this issue, perform one of the following:
4896+ • Re-capture the trace with a shorter duration
4897+ • Re-capture the trace with a larger circular buffer size (e.g., /BufferSize:1024)
4898+ """;
4899+
4900+ XamlMessageBox.Show(
4901+ parentWindow,
4902+ warning,
4903+ "Trace May Be Missing Type Information",
4904+ MessageBoxButton.OK);
4905+ }
4906+ }
4907+
48104908 internal StackSource m_StackSource;
48114909 internal SelectProcess m_SelectProcess;
48124910 private bool m_WarnedAboutBrokenStacks;
@@ -7600,15 +7698,6 @@ You must close and reopen this window to get the allocation types.
76007698 App.UserConfigData["WarnedAboutOsHeapAllocTypes"] = "true";
76017699 }
76027700 }
7603-
7604- // Warn about potentially missing type information due to circular buffer overflow
7605- // This affects views that use GCSampledObjectAllocation (needs BulkType) or GCAllocationTick (needs type info)
7606- if (stackSourceName.StartsWith("GC Heap Alloc Ignore Free") ||
7607- stackSourceName.StartsWith("GC Heap Net Mem") ||
7608- stackSourceName.StartsWith("Gen 2 Object Deaths"))
7609- {
7610- WarnAboutMissingTypeInfo(stackWindow, stackSourceName);
7611- }
76127701 }
76137702
76147703 public override bool SupportsProcesses { get { return true; } }
@@ -8459,71 +8548,8 @@ private bool HasVSEvents(TraceLog traceLog)
84598548 return m_hasVSEvents;
84608549 }
84618550
8462- /// <summary>
8463- /// Checks if the trace has a RuntimeStart event from the Microsoft-Windows-DotNETRuntime provider (not rundown).
8464- /// This indicates that the process was started after tracing began, which is required for proper type information
8465- /// in allocation traces.
8466- /// </summary>
8467- private bool HasRuntimeStartEvent(TraceLog traceLog)
8468- {
8469- if (!m_checkedForRuntimeStart)
8470- {
8471- // Check for RuntimeStart event from the Microsoft-Windows-DotNETRuntime provider
8472- foreach (var stats in traceLog.Stats)
8473- {
8474- // Look for Runtime/Start event from the main CLR provider (not rundown)
8475- if (stats.ProviderGuid == ClrTraceEventParser.ProviderGuid && stats.EventName == "Runtime/Start")
8476- {
8477- m_hasRuntimeStart = true;
8478- break;
8479- }
8480- }
8481-
8482- m_checkedForRuntimeStart = true;
8483- }
8484- return m_hasRuntimeStart;
8485- }
8486-
8487- /// <summary>
8488- /// Shows a warning if the trace may be missing type information due to circular buffer overflow.
8489- /// This checks for the RuntimeStart event which indicates the process started after tracing began.
8490- /// </summary>
8491- private void WarnAboutMissingTypeInfo(StackWindow stackWindow, string viewName)
8492- {
8493- if (m_notifiedAboutMissingTypeInfo)
8494- {
8495- return;
8496- }
8497-
8498- var traceLog = TryGetTraceLog();
8499- if (traceLog != null && !HasRuntimeStartEvent(traceLog))
8500- {
8501- m_notifiedAboutMissingTypeInfo = true;
8502-
8503- var warning = $"""
8504- WARNING: The '{viewName}' view may be missing type information.
8505-
8506- This can happen when the ETW circular buffer wraps and loses early events including type definitions.
8507- Without these type definitions, many types will appear as "UNKNOWN" in the allocation view.
8508-
8509- To fix this issue, perform one of the following:
8510- • Re-capture the trace with a shorter duration
8511- • Re-capture the trace with a larger circular buffer size (e.g., /BufferSize:1024)
8512- """;
8513-
8514- XamlMessageBox.Show(
8515- stackWindow.Owner,
8516- warning,
8517- "Trace May Be Missing Type Information",
8518- MessageBoxButton.OK);
8519- }
8520- }
8521-
85228551 private bool m_checkedForVSEvents;
85238552 private bool m_hasVSEvents;
8524- private bool m_checkedForRuntimeStart;
8525- private bool m_hasRuntimeStart;
8526- private bool m_notifiedAboutMissingTypeInfo;
85278553 private TraceLog m_traceLog;
85288554 private bool m_notifiedAboutLostEvents;
85298555 private bool m_notifiedAboutWin8;
0 commit comments