diff options
author | Sean Gillespie <segilles@microsoft.com> | 2018-01-23 18:53:30 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-23 18:53:30 -0800 |
commit | facdc8b97f73973fb416ed13e4b9dd9a255864bf (patch) | |
tree | c6be1ef07de8d324dcb121da524c13458d7f0f63 /src/gc | |
parent | 0bafdbc71e5a3efe6b6df0cbcf5aee5081a3e4c8 (diff) | |
download | coreclr-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.txt | 1 | ||||
-rw-r--r-- | src/gc/env/gcenv.h | 4 | ||||
-rw-r--r-- | src/gc/env/gcenv.object.h | 5 | ||||
-rw-r--r-- | src/gc/env/gcenv.sync.h | 4 | ||||
-rw-r--r-- | src/gc/gcee.cpp | 9 | ||||
-rw-r--r-- | src/gc/gceesvr.cpp | 1 | ||||
-rw-r--r-- | src/gc/gceewks.cpp | 1 | ||||
-rw-r--r-- | src/gc/gceventstatus.cpp | 9 | ||||
-rw-r--r-- | src/gc/gceventstatus.h | 190 | ||||
-rw-r--r-- | src/gc/gcimpl.h | 4 | ||||
-rw-r--r-- | src/gc/gcinterface.h | 50 | ||||
-rw-r--r-- | src/gc/sample/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/gc/sample/gcenv.h | 4 |
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__ |