Skip to content

Commit 3af4abd

Browse files
Copilotbrianrobmarklio
authored
Add GC Heap Analyzer support to .nettrace files (#2216)
* Initial plan for issue * Add MemoryAnalyzer to EventPipePerfViewData to enable Heap Analyzer for .nettrace files Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> * Move MemoryAnalyzer inside hasGC conditional block Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> * Fix MemoryAnalyzer.Open to support non-ETL formats and single-process files Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> * Fix Toolbox.GetClrProcesses to use full file path for non-clr modules Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> * Refactor code based on review feedback: use pattern matching and simplify path logic Co-authored-by: marklio <529657+marklio@users.noreply.github.com> * Remove unused bool hasClr variable, use out _ instead Co-authored-by: marklio <529657+marklio@users.noreply.github.com> * Update to C# version 8.0. * EventPipe traces don't have a runtime module because they only contain managed loads. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> Co-authored-by: marklio <529657+marklio@users.noreply.github.com> Co-authored-by: Brian Robbins <brianrob@microsoft.com>
1 parent 1189425 commit 3af4abd

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</PropertyGroup>
77

88
<PropertyGroup>
9-
<LangVersion>7.3</LangVersion>
9+
<LangVersion>8.0</LangVersion>
1010
<Features>strict</Features>
1111
</PropertyGroup>
1212

src/PerfView/HeapView/HeapView.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ private Menu CreateMainMenu()
9595
return menu;
9696
}
9797

98+
private TraceLog GetTraceLog(StatusBar worker)
99+
{
100+
return m_dataFile switch
101+
{
102+
ETLPerfViewData etlDataFile => etlDataFile.GetTraceLog(worker.LogWriter),
103+
LinuxPerfViewData linuxDataFile => linuxDataFile.GetTraceLog(worker.LogWriter),
104+
EventPipePerfViewData eventPipeDataFile => eventPipeDataFile.GetTraceLog(worker.LogWriter),
105+
_ => null,
106+
};
107+
}
108+
98109
private void LaunchViewer(List<IProcess> selectedProcesses)
99110
{
100111
// Single process only
@@ -183,28 +194,36 @@ public override void Open(Window parentWindow, StatusBar worker, Action doAfter
183194
{
184195
if (m_dataFile.SupportsProcesses)
185196
{
186-
// Only ETL/ETLX file supported
187-
ETLPerfViewData etlDataFile = m_dataFile as ETLPerfViewData;
197+
// Get TraceLog from the data file (supports multiple formats)
198+
m_traceLog = GetTraceLog(worker);
188199

189-
if (etlDataFile == null)
200+
if (m_traceLog != null)
190201
{
191-
return;
192-
}
202+
m_worker = worker;
193203

194-
m_traceLog = etlDataFile.GetTraceLog(worker.LogWriter);
204+
m_traceLog.SelectClrProcess(LaunchViewer);
205+
}
206+
}
207+
else
208+
{
209+
// Single process format - get the process directly
210+
m_traceLog = GetTraceLog(worker);
195211

196212
if (m_traceLog != null)
197213
{
198214
m_worker = worker;
199215

200-
m_traceLog.SelectClrProcess(LaunchViewer);
216+
var clrProcesses = m_traceLog.GetClrProcesses(out _);
217+
if (clrProcesses.Count > 0)
218+
{
219+
LaunchViewer(clrProcesses);
220+
}
201221
}
202222
}
203223
}
204224
else
205225
{
206226
m_mainWindow.Focus();
207-
208227
doAfter?.Invoke();
209228
}
210229
}

src/PerfView/HeapView/Toolbox.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ internal static bool IsClr(this string name)
735735
{
736736
return name.Equals("clr", StringComparison.OrdinalIgnoreCase) ||
737737
name.Equals("coreclr", StringComparison.OrdinalIgnoreCase) ||
738+
name.Equals("libcoreclr", StringComparison.OrdinalIgnoreCase) ||
738739
name.Equals("mscorwks", StringComparison.OrdinalIgnoreCase) ||
739740
name.Equals("mrt100", StringComparison.OrdinalIgnoreCase);
740741
}
@@ -746,6 +747,8 @@ internal static bool IsMscorlib(this string name)
746747
{
747748
return name.Equals("mscorlib", StringComparison.OrdinalIgnoreCase) ||
748749
name.Equals("mscorlib.ni", StringComparison.OrdinalIgnoreCase) ||
750+
name.Equals("system.private.corelib", StringComparison.OrdinalIgnoreCase) ||
751+
name.Equals("system.private.corelib.il", StringComparison.OrdinalIgnoreCase) ||
749752
name.Equals("corefx", StringComparison.OrdinalIgnoreCase);
750753
}
751754

@@ -775,8 +778,6 @@ internal static List<IProcess> GetClrProcesses(this TraceLog traceLog, out bool
775778
{
776779
foreach (TraceLoadedModule m in mods)
777780
{
778-
keep = false;
779-
780781
string name = m.Name;
781782

782783
if (name.IsClr() || name.IsMscorlib() && String.IsNullOrEmpty(clrVersion))
@@ -787,19 +788,16 @@ internal static List<IProcess> GetClrProcesses(this TraceLog traceLog, out bool
787788
{
788789
clrVersion = m.ModuleFile.FilePath;
789790

790-
int pos = clrVersion.LastIndexOf('\\');
791-
792-
if (pos > 0)
791+
// Only extract version from path for clr.dll, for other modules use full path
792+
if (name.Equals("clr", StringComparison.OrdinalIgnoreCase))
793793
{
794-
int p = clrVersion.LastIndexOf('\\', pos - 1);
795-
796-
if (p > 0)
794+
var parentDir = Path.GetDirectoryName(clrVersion);
795+
if (!String.IsNullOrEmpty(parentDir))
797796
{
798-
pos = p;
797+
clrVersion = Path.GetFileName(parentDir);
799798
}
800-
801-
clrVersion = clrVersion.Substring(pos + 1);
802799
}
800+
// For non-clr modules, clrVersion is already set to the full file path above
803801
}
804802

805803
hasClr = true;

src/PerfView/PerfViewData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9564,6 +9564,7 @@ protected override Action<Action> OpenImpl(Window parentWindow, StatusBar worker
95649564
if (hasGC)
95659565
{
95669566
memory.AddChild(new PerfViewGCStats(this));
9567+
memory.AddChild(new MemoryAnalyzer(this));
95679568
}
95689569

95699570
if (hasGCAllocationTicks)

0 commit comments

Comments
 (0)