Skip to content

Commit 40633bd

Browse files
Copilotbrianrob
andcommitted
Refactor to check RuntimeStart per selected process with new OnStackWindowLaunch hook
Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
1 parent b66c972 commit 40633bd

1 file changed

Lines changed: 98 additions & 72 deletions

File tree

src/PerfView/PerfViewData.cs

Lines changed: 98 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)