From ea5a8c3404c94e6a5a73f3237458bcc645418acc Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Tue, 31 Jan 2023 14:25:48 -0800 Subject: [PATCH 1/5] Cap node processing at 10mil and log issue --- .../CommandLine/CollectCommandHandler.cs | 4 ++-- .../DotNetHeapDumpGraphReader.cs | 20 +++++++++++++++++-- .../EventPipeDotNetHeapDumper.cs | 2 +- .../DotNetHeapDump/MemoryGraph.cs | 10 +++++----- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs index d74728d8d9..eeae26d6bb 100644 --- a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs +++ b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs @@ -116,8 +116,8 @@ internal static bool TryCollectMemoryGraph(CancellationToken ct, int processId, { var heapInfo = new DotNetHeapInfo(); var log = verbose ? Console.Out : TextWriter.Null; - - memoryGraph = new MemoryGraph(50_000); + + memoryGraph = new MemoryGraph(expectedSize: 500_000, isVeryLargeGraph: true); if (!EventPipeDotNetHeapDumper.DumpFromEventPipe(ct, processId, memoryGraph, log, timeout, heapInfo)) { diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs index 8d7836c4b9..fc55fefc5d 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs @@ -512,6 +512,7 @@ internal unsafe void ConvertHeapDataToGraph() } m_converted = true; + const int MaxNodeCount = 10_000_000; if (!m_seenStart) { @@ -712,11 +713,26 @@ internal unsafe void ConvertHeapDataToGraph() Debug.Assert(!m_graph.IsDefined(nodeIdx)); m_graph.SetNode(nodeIdx, typeIdx, objSize, m_children); + + if (m_graph.NodeCount >= MaxNodeCount) + { + doCompletionCheck = false; + m_log.WriteLine("[WARNING: ]", + $"Exceeded max node count {MaxNodeCount}. Processed {m_curNodeIdx}/{m_curNodeBlock.Count} nodes with {m_nodeBlocks.Count} node bulk events to go."); + break; + } } - if (doCompletionCheck && m_curEdgeBlock != null && m_curEdgeBlock.Count != m_curEdgeIdx) + + if (m_curEdgeBlock != null && m_curEdgeBlock.Count != m_curEdgeIdx) { - throw new ApplicationException("Error: extra edge data. Giving up on heap dump."); + m_log.WriteLine("[WARNING: ]", + $"Extra edge data found. Processing edge {m_curEdgeIdx}/{m_curEdgeBlock.Count} with {m_edgeBlocks.Count} edge bulk events to go."); + + if (doCompletionCheck) + { + throw new ApplicationException("Error: Giving up on heap dump."); + } } m_root.Build(); diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs index 64a040d964..3d7afce00e 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs @@ -87,7 +87,7 @@ public static bool DumpFromEventPipe(CancellationToken ct, int processID, Memory eventPipeDataPresent = true; - if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC) + if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC && data.Reason == GCReason.Induced) { gcNum = data.Count; log.WriteLine("{0,5:n1}s: .NET Dump Started...", getElapsed().TotalSeconds); diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs index bb60ef3bff..682ae98beb 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs @@ -19,10 +19,10 @@ public MemoryGraph(int expectedSize, bool isVeryLargeGraph = false) m_addressToNodeIndex = new SegmentedDictionary(expectedSize); } else - { - m_addressToNodeIndex = new Dictionary(expectedSize); + { + m_addressToNodeIndex = new Dictionary(expectedSize); } - + m_nodeAddresses = new SegmentedList
(SegmentSize, expectedSize); } @@ -133,13 +133,13 @@ void IFastSerializable.ToStream(Serializer serializer) // Write out the Memory addresses of each object if (m_isVeryLargeGraph) { - serializer.Write(m_nodeAddresses.Count); + serializer.Write(m_nodeAddresses.Count); } else { serializer.Write((int)m_nodeAddresses.Count); } - + for (int i = 0; i < m_nodeAddresses.Count; i++) { serializer.Write((long)m_nodeAddresses[i]); From ca124a2a44d7e8c39041007e41661944cdefafd3 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Tue, 31 Jan 2023 15:20:03 -0800 Subject: [PATCH 2/5] Remove changes around sparse graph representation --- src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs index eeae26d6bb..d74728d8d9 100644 --- a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs +++ b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs @@ -116,8 +116,8 @@ internal static bool TryCollectMemoryGraph(CancellationToken ct, int processId, { var heapInfo = new DotNetHeapInfo(); var log = verbose ? Console.Out : TextWriter.Null; - - memoryGraph = new MemoryGraph(expectedSize: 500_000, isVeryLargeGraph: true); + + memoryGraph = new MemoryGraph(50_000); if (!EventPipeDotNetHeapDumper.DumpFromEventPipe(ct, processId, memoryGraph, log, timeout, heapInfo)) { From 1684b6dd6c64f2374449752ea846a1d04dbb674f Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Tue, 31 Jan 2023 16:12:11 -0800 Subject: [PATCH 3/5] Make sure to mark heap as 64 bit dependent on GC pointer sizes --- .../dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs index 3d7afce00e..3e2a91b802 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs @@ -90,6 +90,7 @@ public static bool DumpFromEventPipe(CancellationToken ct, int processID, Memory if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC && data.Reason == GCReason.Induced) { gcNum = data.Count; + memoryGraph.Is64Bit = data.PointerSize == 8; log.WriteLine("{0,5:n1}s: .NET Dump Started...", getElapsed().TotalSeconds); } }; From 2898bed0d957963f6f3dbecb2c3200da3f96924c Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Tue, 31 Jan 2023 16:41:03 -0800 Subject: [PATCH 4/5] Fix logging statements --- .../DotNetHeapDump/DotNetHeapDumpGraphReader.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs index fc55fefc5d..7a8c268975 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/DotNetHeapDumpGraphReader.cs @@ -717,8 +717,8 @@ internal unsafe void ConvertHeapDataToGraph() if (m_graph.NodeCount >= MaxNodeCount) { doCompletionCheck = false; - m_log.WriteLine("[WARNING: ]", - $"Exceeded max node count {MaxNodeCount}. Processed {m_curNodeIdx}/{m_curNodeBlock.Count} nodes with {m_nodeBlocks.Count} node bulk events to go."); + m_log.WriteLine("[WARNING]: Exceeded max node count {0}. Processed {1}/{2} nodes with {3} node bulk events to go.", + MaxNodeCount, m_curNodeIdx, m_curNodeBlock.Count, m_nodeBlocks.Count); break; } } @@ -726,8 +726,8 @@ internal unsafe void ConvertHeapDataToGraph() if (m_curEdgeBlock != null && m_curEdgeBlock.Count != m_curEdgeIdx) { - m_log.WriteLine("[WARNING: ]", - $"Extra edge data found. Processing edge {m_curEdgeIdx}/{m_curEdgeBlock.Count} with {m_edgeBlocks.Count} edge bulk events to go."); + m_log.WriteLine("[WARNING]: Extra edge data found. Processing edge {0}/{1} with {2} edge bulk events to go.", + m_curEdgeIdx, m_curEdgeBlock.Count, m_edgeBlocks.Count); if (doCompletionCheck) { From 9b2ca563c50c3bd485b624faa46df6c3681393dc Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Tue, 31 Jan 2023 17:36:53 -0800 Subject: [PATCH 5/5] Revert unnecessary changes --- .../DotNetHeapDump/EventPipeDotNetHeapDumper.cs | 3 +-- src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs index 3e2a91b802..64a040d964 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/EventPipeDotNetHeapDumper.cs @@ -87,10 +87,9 @@ public static bool DumpFromEventPipe(CancellationToken ct, int processID, Memory eventPipeDataPresent = true; - if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC && data.Reason == GCReason.Induced) + if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC) { gcNum = data.Count; - memoryGraph.Is64Bit = data.PointerSize == 8; log.WriteLine("{0,5:n1}s: .NET Dump Started...", getElapsed().TotalSeconds); } }; diff --git a/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs b/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs index 682ae98beb..bb60ef3bff 100644 --- a/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs +++ b/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs @@ -19,10 +19,10 @@ public MemoryGraph(int expectedSize, bool isVeryLargeGraph = false) m_addressToNodeIndex = new SegmentedDictionary(expectedSize); } else - { - m_addressToNodeIndex = new Dictionary(expectedSize); + { + m_addressToNodeIndex = new Dictionary(expectedSize); } - + m_nodeAddresses = new SegmentedList
(SegmentSize, expectedSize); } @@ -133,13 +133,13 @@ void IFastSerializable.ToStream(Serializer serializer) // Write out the Memory addresses of each object if (m_isVeryLargeGraph) { - serializer.Write(m_nodeAddresses.Count); + serializer.Write(m_nodeAddresses.Count); } else { serializer.Write((int)m_nodeAddresses.Count); } - + for (int i = 0; i < m_nodeAddresses.Count; i++) { serializer.Write((long)m_nodeAddresses[i]);