-
Notifications
You must be signed in to change notification settings - Fork 752
Add GC Heap Analyzer support to .nettrace files #2216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…or .nettrace files Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
src/PerfView/PerfViewData.cs
Outdated
| memory.AddChild(new PerfViewGCStats(this)); | ||
| } | ||
|
|
||
| memory.AddChild(new MemoryAnalyzer(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put this inside the hasGC if statement above so it only shows up if there are GC events present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Moved the MemoryAnalyzer inside the hasGC if block so it only appears when GC events are present. (75be7c2)
Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
| if (hasGC) | ||
| { | ||
| memory.AddChild(new PerfViewGCStats(this)); | ||
| memory.AddChild(new MemoryAnalyzer(this)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a partial implementation, but more is required. When some one double clicks on the "GC Heap Analyzer" option, it calls MemoryAnalyzer.Open. This method is responsible for picking the process of interest and then calling LaunchViewer. When there are multiple processes, it does this by calling SelectClrProcess, passing a delegate to LaunchViewer.
MemoryAnalyzer.Open needs two changes:
- If
SupportsProcessesisfalse, then get the one process from theTraceLog, and directly callLaunchViewer. - Remove the limitation that the input file must be an
ETLPerfViewDatafile, since there are now other multi-process formats that are supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented the requested changes to MemoryAnalyzer.Open:
- Removed ETLPerfViewData limitation: Added
GetTraceLoghelper method that supports ETL, Linux, and EventPipe data formats - Added single-process support: When
SupportsProcessesis false, the method now gets CLR processes directly from TraceLog and callsLaunchViewerwithout user selection
The implementation handles both multi-process and single-process scenarios properly. (fc742bf)
… files Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
|
@copilot, please modify |
Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com>
Fixed the |
|
Copilot post-mortem:
|
mconnew
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
![]()
marklio
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments worth looking at here.
src/PerfView/HeapView/HeapView.cs
Outdated
|
|
||
| private TraceLog GetTraceLog(StatusBar worker) | ||
| { | ||
| var etlDataFile = m_dataFile as ETLPerfViewData; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CONSIDER: I really like pattern matching for stuff like this (you can even change this into an expression-bodied method so that switch expression IS the body):
return m_dataFile switch
{
ETLPerfViewData etlDataFile => etlDataFile.GetTraceLog(worker.LogWriter),
LinuxPerfViewData linuxDataFile => linuxDataFile.GetTraceLog(worker.LogWriter),
EventPipePerfViewData eventPipeDataFile => eventPipeDataFile.GetTraceLog(worker.LogWriter),
_ => null,
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if you don't like switch expressions, you can do if (m_dataFile is ETLPerfViewData etlDataFile) rather than the as/if combo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented using switch expressions as suggested. The GetTraceLog method is now more concise and readable. (05ed532)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used switch expressions instead, which is even cleaner than the "is" pattern approach. (05ed532)
src/PerfView/HeapView/HeapView.cs
Outdated
| m_worker = worker; | ||
|
|
||
| m_traceLog.SelectClrProcess(LaunchViewer); | ||
| bool hasClr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the unnecessary empty line. (05ed532)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't referring to an empty line. It looks like you added "bool hasClr;", but it doesn't appear to be used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I see. it's used as an out parameter in GetClrProcesses, but isn't used after. Consider using a discard instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right - I removed the unused bool hasClr; variable and replaced it with out _ to discard the unwanted out parameter. (5b82546)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Replaced the unused bool hasClr variable with out _ to discard the unwanted out parameter. (5b82546)
|
|
||
| if (pos > 0) | ||
| // Only extract version from path for clr.dll, for other modules use full path | ||
| if (name.Equals("clr", StringComparison.OrdinalIgnoreCase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CONSIDER: This is all more easily readable with Path.GetFileName(Path.GetDirectoryName(path)) with maybe some sanity checks around the input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored to use Path.GetFileName(Path.GetDirectoryName(path)) as suggested. Much cleaner and more readable than the manual string manipulation. (05ed532)
…lify path logic Co-authored-by: marklio <529657+marklio@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addressesI tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
Co-authored-by: marklio <529657+marklio@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addressesI tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
This PR adds the missing GC Heap Analyzer functionality to .nettrace files to match the capabilities available in ETLX files.
Problem
When opening .nettrace files in PerfView, users don't see the "Memory Analyzer" (Heap Analyzer) option that's available when opening ETLX files, even though the underlying data may support heap analysis.
Solution
Added the
MemoryAnalyzerto theEventPipePerfViewData.OpenImpl()method, mirroring how it's implemented inETLPerfViewData.Changes made:
memory.AddChild(new MemoryAnalyzer(this));inEventPipePerfViewData.OpenImpl()at line 9565Result
.nettrace files now provide the same heap analysis capabilities as ETLX files, eliminating the need for users to convert files to access heap analysis features.
Before:
After:
Fixes #2026.
Warning
Firewall rules blocked me from connecting to one or more addresses
I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.