summaryrefslogtreecommitdiff
path: root/src/gc
diff options
context:
space:
mode:
authorSean Gillespie <segilles@microsoft.com>2018-01-23 18:53:30 -0800
committerGitHub <noreply@github.com>2018-01-23 18:53:30 -0800
commitfacdc8b97f73973fb416ed13e4b9dd9a255864bf (patch)
treec6be1ef07de8d324dcb121da524c13458d7f0f63 /src/gc
parent0bafdbc71e5a3efe6b6df0cbcf5aee5081a3e4c8 (diff)
downloadcoreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.tar.gz
coreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.tar.bz2
coreclr-facdc8b97f73973fb416ed13e4b9dd9a255864bf.zip
[Local GC] FEATURE_EVENT_TRACE 1/n: Tracking Event State (#15873)
* [Local GC] FEATURE_EVENT_TRACE 1/n: Add infrastructure for keeping event state within the GC and plumbing to communicate event state changes * Code review feedback: use a load without a barrier in IsEnabled and put debug-only code under TRACE_GC_EVENT_STATE * Address code review feedback: add EventPipe callback and comments * Fix the non-FEATURE_PAL build * Fix an issue where the GC fails to react to ETW callbacks to occur before the GC is initialized (e.g. on startup when an ETW session is already active) * Simplify callback locking scheme * Add a separate callback for each EventPipe provider and funnel them all through a common handler * Fix non-FEATURE_PAL build
Diffstat (limited to 'src/gc')
-rw-r--r--src/gc/CMakeLists.txt1
-rw-r--r--src/gc/env/gcenv.h4
-rw-r--r--src/gc/env/gcenv.object.h5
-rw-r--r--src/gc/env/gcenv.sync.h4
-rw-r--r--src/gc/gcee.cpp9
-rw-r--r--src/gc/gceesvr.cpp1
-rw-r--r--src/gc/gceewks.cpp1
-rw-r--r--src/gc/gceventstatus.cpp9
-rw-r--r--src/gc/gceventstatus.h190
-rw-r--r--src/gc/gcimpl.h4
-rw-r--r--src/gc/gcinterface.h50
-rw-r--r--src/gc/sample/CMakeLists.txt1
-rw-r--r--src/gc/sample/gcenv.h4
13 files changed, 283 insertions, 0 deletions
diff --git a/src/gc/CMakeLists.txt b/src/gc/CMakeLists.txt
index 3240074b9b..e7aacdb831 100644
--- a/src/gc/CMakeLists.txt
+++ b/src/gc/CMakeLists.txt
@@ -18,6 +18,7 @@ remove_definitions(-DWRITE_BARRIER_CHECK)
add_definitions(-DFEATURE_REDHAWK)
set( GC_SOURCES
+ gceventstatus.cpp
gcconfig.cpp
gccommon.cpp
gcscan.cpp
diff --git a/src/gc/env/gcenv.h b/src/gc/env/gcenv.h
index 3de756021d..a3071a1397 100644
--- a/src/gc/env/gcenv.h
+++ b/src/gc/env/gcenv.h
@@ -1,6 +1,8 @@
// 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.
+#ifndef __GCENV_H__
+#define __GCENV_H__
#if defined(_DEBUG)
#ifndef _DEBUG_IMPL
@@ -71,3 +73,5 @@
#include "etmdummy.h"
#define ETW_EVENT_ENABLED(e,f) false
+
+#endif // __GCENV_H__
diff --git a/src/gc/env/gcenv.object.h b/src/gc/env/gcenv.object.h
index 4d611e562d..dd152f2f3c 100644
--- a/src/gc/env/gcenv.object.h
+++ b/src/gc/env/gcenv.object.h
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#ifndef __GCENV_OBJECT_H__
+#define __GCENV_OBJECT_H__
+
//-------------------------------------------------------------------------------------------------
//
// Low-level types describing GC object layouts.
@@ -168,3 +171,5 @@ public:
return offsetof(ArrayBase, m_dwLength);
}
};
+
+#endif // __GCENV_OBJECT_H__
diff --git a/src/gc/env/gcenv.sync.h b/src/gc/env/gcenv.sync.h
index d6bee05a19..5b7b77ddd4 100644
--- a/src/gc/env/gcenv.sync.h
+++ b/src/gc/env/gcenv.sync.h
@@ -1,6 +1,8 @@
// 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.
+#ifndef __GCENV_SYNC_H__
+#define __GCENV_SYNC_H__
// -----------------------------------------------------------------------------------------------------------
//
@@ -143,3 +145,5 @@ private:
HANDLE m_hEvent;
bool m_fInitialized;
};
+
+#endif // __GCENV_SYNC_H__
diff --git a/src/gc/gcee.cpp b/src/gc/gcee.cpp
index 90939b3d97..c5cc88b373 100644
--- a/src/gc/gcee.cpp
+++ b/src/gc/gcee.cpp
@@ -687,6 +687,15 @@ bool GCHeap::RuntimeStructuresValid()
return GCScan::GetGcRuntimeStructuresValid();
}
+void GCHeap::ControlEvents(GCEventKeyword keyword, GCEventLevel level)
+{
+ GCEventStatus::Set(GCEventProvider_Default, keyword, level);
+}
+
+void GCHeap::ControlPrivateEvents(GCEventKeyword keyword, GCEventLevel level)
+{
+ GCEventStatus::Set(GCEventProvider_Private, keyword, level);
+}
#endif // !DACCESS_COMPILE
diff --git a/src/gc/gceesvr.cpp b/src/gc/gceesvr.cpp
index e216834f8e..cfcbe5869a 100644
--- a/src/gc/gceesvr.cpp
+++ b/src/gc/gceesvr.cpp
@@ -13,6 +13,7 @@
#include "gc.h"
#include "gcscan.h"
#include "gchandletableimpl.h"
+#include "gceventstatus.h"
#define SERVER_GC 1
diff --git a/src/gc/gceewks.cpp b/src/gc/gceewks.cpp
index f23038f012..9a4038cdd9 100644
--- a/src/gc/gceewks.cpp
+++ b/src/gc/gceewks.cpp
@@ -11,6 +11,7 @@
#include "gc.h"
#include "gcscan.h"
#include "gchandletableimpl.h"
+#include "gceventstatus.h"
#ifdef SERVER_GC
#undef SERVER_GC
diff --git a/src/gc/gceventstatus.cpp b/src/gc/gceventstatus.cpp
new file mode 100644
index 0000000000..9c4f35bfde
--- /dev/null
+++ b/src/gc/gceventstatus.cpp
@@ -0,0 +1,9 @@
+// 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.
+
+#include "common.h"
+#include "gceventstatus.h"
+
+Volatile<GCEventLevel> GCEventStatus::enabledLevels[2] = {GCEventLevel_None, GCEventLevel_None};
+Volatile<GCEventKeyword> GCEventStatus::enabledKeywords[2] = {GCEventKeyword_None, GCEventKeyword_None};
diff --git a/src/gc/gceventstatus.h b/src/gc/gceventstatus.h
new file mode 100644
index 0000000000..4b7310b8a7
--- /dev/null
+++ b/src/gc/gceventstatus.h
@@ -0,0 +1,190 @@
+// 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.
+
+#ifndef __GCEVENTSTATUS_H__
+#define __GCEVENTSTATUS_H__
+
+
+/*
+ * gceventstatus.h - Eventing status for a standalone GC
+ *
+ * In order for a local GC to determine what events are enabled
+ * in an efficient manner, the GC maintains some local state about
+ * keywords and levels that are enabled for each eventing provider.
+ *
+ * The GC fires events from two providers: the "main" provider
+ * and the "private" provider. This file tracks keyword and level
+ * information for each provider separately.
+ *
+ * It is the responsibility of the EE to inform the GC of changes
+ * to eventing state. This is accomplished by invoking the
+ * `IGCHeap::ControlEvents` and `IGCHeap::ControlPrivateEvents` callbacks
+ * on the EE's heap instance, which ultimately will enable and disable keywords
+ * and levels within this file.
+ */
+
+#include "common.h"
+#include "gcenv.h"
+#include "gc.h"
+
+// Uncomment this define to print out event state changes to standard error.
+// #define TRACE_GC_EVENT_STATE 1
+
+/*
+ * GCEventProvider represents one of the two providers that the GC can
+ * fire events from: the default and private providers.
+ */
+enum GCEventProvider
+{
+ GCEventProvider_Default = 0,
+ GCEventProvider_Private = 1
+};
+
+/*
+ * GCEventStatus maintains all eventing state for the GC. It consists
+ * of a keyword bitmask and level for each provider that the GC can use
+ * to fire events.
+ *
+ * A level and event pair are considered to be "enabled" on a given provider
+ * if the given level is less than or equal to the current enabled level
+ * and if the keyword is present in the enabled keyword bitmask for that
+ * provider.
+ */
+class GCEventStatus
+{
+private:
+ /*
+ * The enabled level for each provider.
+ */
+ static Volatile<GCEventLevel> enabledLevels[2];
+
+ /*
+ * The bitmap of enabled keywords for each provider.
+ */
+ static Volatile<GCEventKeyword> enabledKeywords[2];
+
+public:
+ /*
+ * IsEnabled queries whether or not the given level and keyword are
+ * enabled on the given provider, returning true if they are.
+ */
+ __forceinline static bool IsEnabled(GCEventProvider provider, GCEventKeyword keyword, GCEventLevel level)
+ {
+ assert(level >= GCEventLevel_None && level < GCEventLevel_Max);
+
+ size_t index = static_cast<size_t>(provider);
+ return (enabledLevels[index].LoadWithoutBarrier() >= level)
+ && (enabledKeywords[index].LoadWithoutBarrier() & keyword);
+ }
+
+ /*
+ * Set sets the eventing state (level and keyword bitmap) for a given
+ * provider to the provided values.
+ */
+ static void Set(GCEventProvider provider, GCEventKeyword keywords, GCEventLevel level)
+ {
+ assert(level >= GCEventLevel_None && level < GCEventLevel_Max);
+
+ size_t index = static_cast<size_t>(provider);
+
+ enabledLevels[index] = level;
+ enabledKeywords[index] = keywords;
+
+#if TRACE_GC_EVENT_STATE
+ fprintf(stderr, "event state change:\n");
+ DebugDumpState(provider);
+#endif // TRACE_GC_EVENT_STATE
+ }
+
+#if TRACE_GC_EVENT_STATE
+private:
+ static void DebugDumpState(GCEventProvider provider)
+ {
+ size_t index = static_cast<size_t>(provider);
+ GCEventLevel level = enabledLevels[index];
+ GCEventKeyword keyword = enabledKeywords[index];
+ if (provider == GCEventProvider_Default)
+ {
+ fprintf(stderr, "provider: default\n");
+ }
+ else
+ {
+ fprintf(stderr, "provider: private\n");
+ }
+
+ switch (level)
+ {
+ case GCEventLevel_None:
+ fprintf(stderr, " level: None\n");
+ break;
+ case GCEventLevel_Fatal:
+ fprintf(stderr, " level: Fatal\n");
+ break;
+ case GCEventLevel_Error:
+ fprintf(stderr, " level: Error\n");
+ break;
+ case GCEventLevel_Warning:
+ fprintf(stderr, " level: Warning\n");
+ break;
+ case GCEventLevel_Information:
+ fprintf(stderr, " level: Information\n");
+ break;
+ case GCEventLevel_Verbose:
+ fprintf(stderr, " level: Verbose\n");
+ break;
+ default:
+ fprintf(stderr, " level: %d?\n", level);
+ break;
+ }
+
+ fprintf(stderr, " keywords: ");
+ if (keyword & GCEventKeyword_GC)
+ {
+ fprintf(stderr, "GC ");
+ }
+
+ if (keyword & GCEventKeyword_GCHandle)
+ {
+ fprintf(stderr, "GCHandle ");
+ }
+
+ if (keyword & GCEventKeyword_GCHeapDump)
+ {
+ fprintf(stderr, "GCHeapDump ");
+ }
+
+ if (keyword & GCEventKeyword_GCSampledObjectAllocationHigh)
+ {
+ fprintf(stderr, "GCSampledObjectAllocationHigh ");
+ }
+
+ if (keyword & GCEventKeyword_GCHeapSurvivalAndMovement)
+ {
+ fprintf(stderr, "GCHeapSurvivalAndMovement ");
+ }
+
+ if (keyword & GCEventKeyword_GCHeapCollect)
+ {
+ fprintf(stderr, "GCHeapCollect ");
+ }
+
+ if (keyword & GCEventKeyword_GCHeapAndTypeNames)
+ {
+ fprintf(stderr, "GCHeapAndTypeNames ");
+ }
+
+ if (keyword & GCEventKeyword_GCSampledObjectAllocationLow)
+ {
+ fprintf(stderr, "GCSampledObjectAllocationLow ");
+ }
+
+ fprintf(stderr, "\n");
+ }
+#endif // TRACE_GC_EVENT_STATUS
+
+ // This class is a singleton and can't be instantiated.
+ GCEventStatus() = delete;
+};
+
+#endif // __GCEVENTSTATUS_H__
diff --git a/src/gc/gcimpl.h b/src/gc/gcimpl.h
index c0efa69531..7210b9bcf0 100644
--- a/src/gc/gcimpl.h
+++ b/src/gc/gcimpl.h
@@ -230,6 +230,10 @@ public: // FIX
virtual segment_handle RegisterFrozenSegment(segment_info *pseginfo);
virtual void UnregisterFrozenSegment(segment_handle seg);
+ // Event control functions
+ void ControlEvents(GCEventKeyword keyword, GCEventLevel level);
+ void ControlPrivateEvents(GCEventKeyword keyword, GCEventLevel level);
+
void WaitUntilConcurrentGCComplete (); // Use in managd threads
#ifndef DACCESS_COMPILE
HRESULT WaitUntilConcurrentGCCompleteAsync(int millisecondsTimeout); // Use in native threads. TRUE if succeed. FALSE if failed or timeout
diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h
index afd3db3fe4..26e7c096d2 100644
--- a/src/gc/gcinterface.h
+++ b/src/gc/gcinterface.h
@@ -205,6 +205,44 @@ extern uint8_t* g_shadow_lowest_address;
// For low memory notification from host
extern int32_t g_bLowMemoryFromHost;
+// Event levels corresponding to events that can be fired by the GC.
+enum GCEventLevel
+{
+ GCEventLevel_None = 0,
+ GCEventLevel_Fatal = 1,
+ GCEventLevel_Error = 2,
+ GCEventLevel_Warning = 3,
+ GCEventLevel_Information = 4,
+ GCEventLevel_Verbose = 5,
+ GCEventLevel_Max = 6
+};
+
+// Event keywords corresponding to events that can be fired by the GC. These
+// numbers come from the ETW manifest itself - please make changes to this enum
+// if you add, remove, or change keyword sets that are used by the GC!
+enum GCEventKeyword
+{
+ GCEventKeyword_None = 0x0,
+ GCEventKeyword_GC = 0x1,
+ GCEventKeyword_GCHandle = 0x2,
+ GCEventKeyword_GCHeapDump = 0x100000,
+ GCEventKeyword_GCSampledObjectAllocationHigh = 0x200000,
+ GCEventKeyword_GCHeapSurvivalAndMovement = 0x400000,
+ GCEventKeyword_GCHeapCollect = 0x800000,
+ GCEventKeyword_GCHeapAndTypeNames = 0x1000000,
+ GCEventKeyword_GCSampledObjectAllocationLow = 0x2000000,
+ GCEventKeyword_All = GCEventKeyword_GC
+ | GCEventKeyword_GCHandle
+ | GCEventKeyword_GCHeapDump
+ | GCEventKeyword_GCSampledObjectAllocationHigh
+ | GCEventKeyword_GCHeapDump
+ | GCEventKeyword_GCSampledObjectAllocationHigh
+ | GCEventKeyword_GCHeapSurvivalAndMovement
+ | GCEventKeyword_GCHeapCollect
+ | GCEventKeyword_GCHeapAndTypeNames
+ | GCEventKeyword_GCSampledObjectAllocationLow
+};
+
// !!!!!!!!!!!!!!!!!!!!!!!
// make sure you change the def in bcl\system\gc.cs
// if you change this!
@@ -809,6 +847,18 @@ public:
// Unregisters a frozen segment.
virtual void UnregisterFrozenSegment(segment_handle seg) = 0;
+ /*
+ ===========================================================================
+ Routines for informing the GC about which events are enabled.
+ ===========================================================================
+ */
+
+ // Enables or disables the given keyword or level on the default event provider.
+ virtual void ControlEvents(GCEventKeyword keyword, GCEventLevel level) = 0;
+
+ // Enables or disables the given keyword or level on the private event provider.
+ virtual void ControlPrivateEvents(GCEventKeyword keyword, GCEventLevel level) = 0;
+
IGCHeap() {}
virtual ~IGCHeap() {}
};
diff --git a/src/gc/sample/CMakeLists.txt b/src/gc/sample/CMakeLists.txt
index 6f8aa615d7..953d0498e0 100644
--- a/src/gc/sample/CMakeLists.txt
+++ b/src/gc/sample/CMakeLists.txt
@@ -10,6 +10,7 @@ add_definitions(-DFEATURE_REDHAWK)
set(SOURCES
GCSample.cpp
gcenv.ee.cpp
+ ../gceventstatus.cpp
../gcconfig.cpp
../gccommon.cpp
../gceewks.cpp
diff --git a/src/gc/sample/gcenv.h b/src/gc/sample/gcenv.h
index a86cf535d5..54b596e141 100644
--- a/src/gc/sample/gcenv.h
+++ b/src/gc/sample/gcenv.h
@@ -1,6 +1,8 @@
// 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.
+#ifndef __GCENV_H__
+#define __GCENV_H__
// The sample is to be kept simple, so building the sample
// in tandem with a standalone GC is currently not supported.
@@ -200,3 +202,5 @@ extern EEConfig * g_pConfig;
#include "etmdummy.h"
#define ETW_EVENT_ENABLED(e,f) false
+
+#endif // __GCENV_H__