Fix GC heap dump (#38893)
authorDavid Mason <davmason@microsoft.com>
Thu, 9 Jul 2020 21:32:11 +0000 (14:32 -0700)
committerGitHub <noreply@github.com>
Thu, 9 Jul 2020 21:32:11 +0000 (14:32 -0700)
#36932 had a typo that caused types to never be logged

src/coreclr/src/vm/eventtrace.cpp
src/coreclr/tests/issues.targets
src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.cs [new file with mode: 0644]
src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.csproj [new file with mode: 0644]

index 0d414d3..8ec7020 100644 (file)
@@ -3559,7 +3559,7 @@ BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * p
     {
         CrstHolder _crst(GetHashCrst());
         // Like above, check if the type has been added from a different thread since we last looked it up.
-        if (pLoggedTypesFromModule->loggedTypesFromModuleHash.Lookup(th).th.IsNull())
+        if (!pLoggedTypesFromModule->loggedTypesFromModuleHash.Lookup(th).th.IsNull())
         {
             *pfCreatedNew = FALSE;
             return fSucceeded;
index 4f3b248..0962c1b 100644 (file)
         <ExcludeList Include="$(XunitTestBinBase)/tracing/tracevalidation/tracelogging/tracelogging/**">
             <Issue>needs triage</Issue>
         </ExcludeList>
+        <ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/gcdump/gcdump/**">
+            <Issue>needs triage</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/readytorun/coreroot_determinism/coreroot_determinism/**">
             <Issue>needs triage</Issue>
         </ExcludeList>
diff --git a/src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.cs b/src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.cs
new file mode 100644 (file)
index 0000000..1ee96f8
--- /dev/null
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Tracing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Microsoft.Diagnostics.NETCore.Client;
+using Microsoft.Diagnostics.Tools.RuntimeClient;
+using Microsoft.Diagnostics.Tracing;
+using Microsoft.Diagnostics.Tracing.Parsers;
+using Tracing.Tests.Common;
+using Microsoft.Diagnostics.Tracing.Parsers.Clr;
+
+namespace Tracing.Tests.EventSourceError
+{
+    // Regression test for https://github.com/dotnet/runtime/issues/38639 
+    public class GCDumpTest
+    {
+        private static int _bulkTypeCount = 0;
+        private static int _bulkNodeCount = 0;
+        private static int _bulkEdgeCount = 0;
+        private static int _bulkRootEdgeCount = 0;
+        private static int _bulkRootStaticVarCount = 0;
+
+        private static readonly ulong GC_HeapDump_Keyword = 0x100000UL;
+
+        public static int Main(string[] args)
+        {
+            // This test validates that if an EventSource generates an error
+            // during construction it gets emitted over EventPipe
+
+            List<Provider> providers = new List<Provider>
+            {
+                new Provider("Microsoft-Windows-DotNETRuntime", eventLevel: EventLevel.Verbose, keywords: (ulong)ClrTraceEventParser.Keywords.GCHeapSnapshot)
+            };
+
+            var configuration = new SessionConfiguration(circularBufferSizeMB: 1024, format: EventPipeSerializationFormat.NetTrace,  providers: providers);
+            return IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration, _DoesRundownContainMethodEvents);
+        }
+
+        private static Dictionary<string, ExpectedEventCount> _expectedEventCounts = new Dictionary<string, ExpectedEventCount>()
+        {
+            // This space intentionally left blank
+        };
+
+        private static Action _eventGeneratingAction = () =>
+        {
+            // This space intentionally left blank
+        };
+
+        private static Func<EventPipeEventSource, Func<int>> _DoesRundownContainMethodEvents = (source) =>
+        {
+            source.Clr.TypeBulkType += (GCBulkTypeTraceData data) =>
+            {
+                _bulkTypeCount += data.Count;
+            };
+
+            source.Clr.GCBulkNode += delegate (GCBulkNodeTraceData data)
+            {
+                _bulkNodeCount += data.Count;
+            };
+
+            source.Clr.GCBulkEdge += (GCBulkEdgeTraceData data) =>
+            {
+                _bulkEdgeCount += data.Count;
+            };
+
+            source.Clr.GCBulkRootEdge += (GCBulkRootEdgeTraceData data) =>
+            {
+                _bulkRootEdgeCount += data.Count;
+            };
+
+            source.Clr.GCBulkRootStaticVar += (GCBulkRootStaticVarTraceData data) =>
+            {
+                _bulkRootStaticVarCount += data.Count;
+            };
+
+            return () => 
+            {
+                // These values are ~80% (rounded to nice whole numbers) of the values
+                // I saw when writing the test. The idea is that I want to catch
+                // any real deviation in the number of types, but don't want to have
+                // to maintain this test as the number of types varies. (And they will vary due to 
+                // framework code changes). If this test needs any sort of ongoing maintenance
+                // just change all these values to a low number like 10 and move on.
+                if (_bulkTypeCount > 125
+                    && _bulkNodeCount > 600
+                    && _bulkEdgeCount > 850
+                    && _bulkRootEdgeCount > 250
+                    && _bulkRootStaticVarCount > 70)
+                {
+                    return 100;
+                }
+
+
+                Console.WriteLine($"Test failed due to missing GC heap events.");
+                Console.WriteLine($"_bulkTypeCount =          {_bulkTypeCount}");
+                Console.WriteLine($"_bulkNodeCount =          {_bulkNodeCount}");
+                Console.WriteLine($"_bulkEdgeCount =          {_bulkEdgeCount}");
+                Console.WriteLine($"_bulkRootEdgeCount =      {_bulkRootEdgeCount}");
+                Console.WriteLine($"_bulkRootStaticVarCount = {_bulkRootStaticVarCount}");
+                return -1;
+            };
+        };
+    }
+}
\ No newline at end of file
diff --git a/src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.csproj b/src/coreclr/tests/src/tracing/eventpipe/gcdump/gcdump.csproj
new file mode 100644 (file)
index 0000000..a1915b1
--- /dev/null
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
+    <OutputType>exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <UnloadabilityIncompatible>true</UnloadabilityIncompatible>
+    <CLRTestPriority>0</CLRTestPriority>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+    <ProjectReference Include="../common/common.csproj" />
+  </ItemGroup>
+</Project>