Enabled POH in dotnet-dump dumpgen command (#2260)
authorGünther Foidl <gue@korporal.at>
Wed, 19 May 2021 15:57:58 +0000 (17:57 +0200)
committerGitHub <noreply@github.com>
Wed, 19 May 2021 15:57:58 +0000 (08:57 -0700)
* Enabled POH in dotnet-dump dumpgen command

* Tests

* Exclude POH segments from Gen2

* Corrected pattern to match output for x64/x86

For x64 it's 10024, for x86 iit's 10012, so just check for 100<DECVAL>.
I don't want to check just for byte[], as there could be any other byte arrays too.

* Fix dump file names not being unique.

* When the same "TestName" is being used but with different debuggee arguments the resulting dump name
ends up being the same and overwrites the existing one. This caused the uploaded dump to look different
from the log.

* Update CLRMD to patched version for POH analysis

src/Microsoft.Diagnostics.ExtensionCommands/ClrMDHelper.cs
src/Microsoft.Diagnostics.ExtensionCommands/DumpGen.cs
src/Microsoft.Diagnostics.ExtensionCommands/DumpGenCommand.cs
src/Microsoft.Diagnostics.ExtensionCommands/GCGeneration.cs
src/SOS/SOS.UnitTests/Debuggees/DotnetDumpCommands/Program.cs
src/SOS/SOS.UnitTests/SOS.cs
src/SOS/SOS.UnitTests/SOSRunner.cs
src/SOS/SOS.UnitTests/Scripts/DumpGen.script

index 193ff2f17bc8b3ae3fe6a73d8fe6dd24379d071a..9bb4917650f8748120630ac30cee3dd28105c6ee 100644 (file)
@@ -733,7 +733,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                     }
                     return start != end;
                 case GCGeneration.Generation2:
-                    if (!segment.IsLargeObjectSegment)
+                    if (!(segment.IsLargeObjectSegment || segment.IsPinnedObjectSegment))
                     {
                         start = segment.Generation2.Start;
                         end = segment.Generation2.End;
@@ -746,6 +746,13 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                         end = segment.End;
                     }
                     return start != end;
+                case GCGeneration.PinnedObjectHeap:
+                    if (segment.IsPinnedObjectSegment)
+                    {
+                        start = segment.Start;
+                        end = segment.End;
+                    }
+                    return start != end;
                 default:
                     return false;
             }
index cb27b18cfc3d8ddffda3588319a2339a60e99dc9..9261b1c3afeaf9237ac2e80fd09d64c3d83662d8 100644 (file)
@@ -2,14 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using Microsoft.Diagnostics.Runtime;
+using System;
 using System.Collections.Generic;
 using System.Linq;
-using System;
+using Microsoft.Diagnostics.Runtime;
 
 namespace Microsoft.Diagnostics.ExtensionCommands
 {
-
     public class DumpGen
     {
         private readonly ClrMDHelper _helper;
@@ -48,12 +47,9 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                 .Where(obj => obj.Type.MethodTable == methodTableAddress);
         }
 
-
         private static bool IsTypeNameMatching(string typeName, string typeNameFilter)
         {
-            return typeName.ToLower().Contains(typeNameFilter.ToLower());
+            return typeName.IndexOf(typeNameFilter, StringComparison.OrdinalIgnoreCase) >= 0;
         }
-
     }
-
 }
index fbd561d5d593d73232566a43fc7d4acc2a3ab4c7..da86dcbd44fa714ee16e121903c9c41357b1cc96 100644 (file)
@@ -107,8 +107,10 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                     return GCGeneration.Generation2;
                 case "loh":
                     return GCGeneration.LargeObjectHeap;
+                case "poh":
+                    return GCGeneration.PinnedObjectHeap;
                 default:
-                    WriteLine($"{generation} is not a supported generation (gen0, gen1, gen2, loh)");
+                    WriteLine($"{generation} is not a supported generation (gen0, gen1, gen2, loh, poh)");
                     return GCGeneration.NotSet;
             }
         }
@@ -131,6 +133,7 @@ Generation number can take the following values (case insensitive):
 - gen1
 - gen2
 - loh
+- poh
 
 > dumpgen gen0
 Statistics:
index f2652318164c7602f43af5793169a6a04dad9b20..d293a3312338f5e58c3fab19d62b8f6032d9b1c9 100644 (file)
@@ -10,6 +10,7 @@ namespace Microsoft.Diagnostics.ExtensionCommands
         Generation0 = 1,
         Generation1 = 2,
         Generation2 = 3,
-        LargeObjectHeap = 4
+        LargeObjectHeap = 4,
+        PinnedObjectHeap = 5
     }
 }
index 120cddffe1f71e3df2d212a3853afe38327d804d..6afe5e7f825ead0bd628ce45b7c87c805b5478ad 100644 (file)
@@ -127,6 +127,11 @@ namespace DotnetDumpCommands
             // This object should go into LOH
             yield return new DumpSampleClass[50000];
 
+#if NET5_0_OR_GREATER
+            // This object should go into POH
+            yield return GC.AllocateUninitializedArray<byte>(10000, pinned: true);
+#endif
+
             for (var i = 0; i < 5; i++)
             {
                 yield return new DumpSampleClass();
@@ -152,7 +157,6 @@ namespace DotnetDumpCommands
             public DateTime Date { get; set; }
         }
 
-
         public struct DumpSampleStruct
         {
             public int IntValue;
index 20a80e3348eb0e5e6f86cdc3b65c5ab7c3737387..133eadc516fc1850f5d6db441b6807da7f60f5d8 100644 (file)
@@ -138,7 +138,6 @@ public class SOS
         {
             throw new SkipTestException("This test validates POH behavior, which was introduced in .net 5");
         }
-
         await RunTest(config, "GCPOH", "GCPOH.script", testName: "SOS.GCPOHTests", testDump: false);
     }
 
@@ -214,6 +213,7 @@ public class SOS
                 TestName = "SOS.StackAndOtherTests",
                 DebuggeeName = "SymbolTestApp",
                 DebuggeeArguments = "%DEBUG_ROOT%",
+                DumpNameSuffix = currentConfig.DebugType
             });
 
             // This tests using regular Windows PDBs with no managed hosting. SOS should fallback 
@@ -228,6 +228,7 @@ public class SOS
                     TestName = "SOS.StackAndOtherTests",
                     DebuggeeName = "SymbolTestApp",
                     DebuggeeArguments = "%DEBUG_ROOT%",
+                    DumpNameSuffix = currentConfig.DebugType
                 });
             }
         }
@@ -271,7 +272,7 @@ public class SOS
             DebuggeeArguments = desktopTestParameters,
             UsePipeSync = true,
             DumpGenerator = SOSRunner.DumpGenerator.DotNetDump
-        }); ;
+        });
     }
 
     [SkippableTheory, MemberData(nameof(GetConfigurations), "TestName", "DotnetDumpCommands")]
@@ -282,9 +283,10 @@ public class SOS
             TestConfiguration = config,
             DebuggeeName = "DotnetDumpCommands",
             DebuggeeArguments = "dcd",
+            DumpNameSuffix = "dcd",
             UsePipeSync = true,
             DumpGenerator = SOSRunner.DumpGenerator.DotNetDump,
-        }); ;
+        });
     }
 
     [SkippableTheory, MemberData(nameof(GetConfigurations), "TestName", "DotnetDumpCommands")]
@@ -295,9 +297,10 @@ public class SOS
             TestConfiguration = config,
             DebuggeeName = "DotnetDumpCommands",
             DebuggeeArguments = "dumpgen",
+            DumpNameSuffix = "dumpgen",
             UsePipeSync = true,
             DumpGenerator = SOSRunner.DumpGenerator.DotNetDump,
-        }); ;
+        });
     }
 
     [SkippableTheory, MemberData(nameof(Configurations))]
index 53a08befd625d36f7f3d30eb1a1d9bb66ccd2ee8..4ba404e1965904beee9ae15a4888dad72d6d4f75 100644 (file)
@@ -90,6 +90,8 @@ public class SOSRunner : IDisposable
 
         public bool DumpDiagnostics { get; set; } = true;
 
+        public string DumpNameSuffix { get; set; }
+
         public bool IsValid()
         {
             return TestConfiguration != null && OutputHelper != null && DebuggeeName != null;
@@ -973,7 +975,17 @@ public class SOSRunner : IDisposable
         TestConfiguration config = information.TestConfiguration;
         string dumpRoot = action == DebuggerAction.GenerateDump ? config.DebuggeeDumpOutputRootDir() : config.DebuggeeDumpInputRootDir();
         if (!string.IsNullOrEmpty(dumpRoot)) {
-            return Path.Combine(dumpRoot, information.TestName + "." + information.DumpType.ToString() + ".dmp");
+            var sb = new StringBuilder();
+            sb.Append(information.TestName);
+            sb.Append(".");
+            sb.Append(information.DumpType.ToString());
+            if (information.DumpNameSuffix != null)
+            {
+                sb.Append(".");
+                sb.Append(information.DumpNameSuffix);
+            }
+            sb.Append(".dmp");
+            return Path.Combine(dumpRoot, sb.ToString());
         }
         return null;
     }
index 0c8617705f783e817c7f5f15a9f6d4039156d52f..1f8e489cb5c801c3d9ebf676b55d634d8014860e 100644 (file)
@@ -22,7 +22,7 @@ VERIFY: Hexadecimal address expected for -mt option
 
 COMMAND: dumpgen gen0
 VERIFY: ^\s+MT\s+Count\s+TotalSize\s+Class Name
-VERIFY:^<HEXVAL>\s+10\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass
+VERIFY: ^<HEXVAL>\s+10\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass
 
 COMMAND: dumpgen gen0 -type DotnetDumpCommands
 VERIFY: ^<HEXVAL>\s+10\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass
@@ -44,10 +44,16 @@ VERIFY: ^<HEXVAL>\s+3\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass
 
 COMMAND: dumpgen gen2
 VERIFY: ^<HEXVAL>\s+5\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass
+!VERIFY: ^<HEXVAL>\s+1\s+100<DECVAL>\s+System.Byte\[\]
 
 COMMAND: dumpgen loh
 VERIFY: ^<HEXVAL>\s+1\s+<DECVAL>\s+DotnetDumpCommands\.Program\+DumpSampleClass\[\]
 
+IFDEF:MAJOR_RUNTIME_VERSION_GE_5
+COMMAND: dumpgen poh
+VERIFY: ^<HEXVAL>\s+1\s+100<DECVAL>\s+System.Byte\[\]
+ENDIF:MAJOR_RUNTIME_VERSION_GE_5
+
 SOSCOMMAND: dumpheap -stat
 
 ENDIF:NETCORE_OR_DOTNETDUMP