diff options
author | Sean Gillespie <segilles@microsoft.com> | 2018-01-25 18:17:57 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-25 18:17:57 -0800 |
commit | 145cfe19f9e4f3e8a84b75a3048fe98fffb59a68 (patch) | |
tree | 3c993b736f5e07f0b4886453e06591a563d08cc6 /src/gc | |
parent | b7398b0d827248e1eacce251a764feb8bd11d198 (diff) | |
download | coreclr-145cfe19f9e4f3e8a84b75a3048fe98fffb59a68.tar.gz coreclr-145cfe19f9e4f3e8a84b75a3048fe98fffb59a68.tar.bz2 coreclr-145cfe19f9e4f3e8a84b75a3048fe98fffb59a68.zip |
[Local GC] FEATURE_EVENT_TRACE 3/n: Defining and Firing Dynamic Events (#16000)
Diffstat (limited to 'src/gc')
-rw-r--r-- | src/gc/gcevent_serializers.h | 141 | ||||
-rw-r--r-- | src/gc/gcevents.h | 2 | ||||
-rw-r--r-- | src/gc/gceventstatus.h | 68 | ||||
-rw-r--r-- | src/gc/gcinterface.ee.h | 10 | ||||
-rw-r--r-- | src/gc/gcsvr.cpp | 1 | ||||
-rw-r--r-- | src/gc/gcwks.cpp | 1 |
6 files changed, 211 insertions, 12 deletions
diff --git a/src/gc/gcevent_serializers.h b/src/gc/gcevent_serializers.h new file mode 100644 index 0000000000..643ab82a15 --- /dev/null +++ b/src/gc/gcevent_serializers.h @@ -0,0 +1,141 @@ +// 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 __GCEVENT_SERIALIZERS_H__ +#define __GCEVENT_SERIALIZERS_H__ + +/* + * gcevent_serializers.h - Serialization traits and plumbing for + * serializing dynamic events. + * + * Dynamic events are events that can be fired by the GC without prior + * knowledge of the EE. In order to accomplish this, the GC sends raw + * bytes to the EE using the `IGCToCLR::FireDynamicEvent` callback, which + * the EE will then fire as its own event. + * + * In order to keep the friction of adding new dynamic events low, this + * file defines a simple ETW-style binary serialization format that + * is efficient and easy to both serialize and deserialize. + * + * ## Serializing Types + * + * This file makes use of `EventSerializationTraits` to serialize + * types. A type can opt-in to serialization using the mechanisms + * in this file by specializing the `EventSerializationTraits` template, + * providing implementations of `Serialize` and `SerializedSize`. + * + * If you attempt to serialize a type that does not implement this trait, + * you will receive an error message like this: + * + * bool gc_event::EventSerializationTraits<Head>::Serialize(const T&,uint8_t **)': attempting to reference a deleted function + * with + * [ + * Head=<your type you tried to serialize>, + * T=<your type you tried to serialize> + * ] + * + * If you get this message, you will need to specialize `EventSerializationTraits` + * for the type you want to serialize. + */ + +#ifdef _MSC_VER +#define ByteSwap32 _byteswap_ulong +#define ByteSwap64 _byteswap_uint64 +#else +#define ByteSwap32 __bulitin_bswap32 +#define ByteSwap64 __builtin_bswap64 +#endif // MSC_VER + +namespace gc_event +{ + +/* + * `EventSerializatonTraits` is a trait implemented by types that + * can be serialized to the payload of a dynamic event. + */ +template<class T> +struct EventSerializationTraits +{ + /* + * Serializes the value `value` to the buffer `buffer`, incrementing + * the buffer double-pointer to point to the next byte to be written. + * + * It is the responsibility of the caller to ensure that the buffer is + * large enough to accomodate the serialized form of T. + */ + static void Serialize(const T& value, uint8_t** buffer) = delete; + + /* + * Returns the size of the value `value` if it were to be serialized. + */ + static size_t SerializedSize(const T& value) = delete; +}; + +/* + * EventSerializationTraits implementation for uint32_t. Other integral types + * can follow this pattern. + * + * The convention here is that integral types are always serialized as + * little-endian. + */ +template<> +struct EventSerializationTraits<uint32_t> +{ + static void Serialize(const uint32_t& value, uint8_t** buffer) + { +#if defined(BIGENDIAN) + **((uint32_t**)buffer) = ByteSwap32(value); +#else + **((uint32_t**)buffer) = value; +#endif // BIGENDIAN + *buffer += sizeof(uint32_t); + } + + static size_t SerializedSize(const uint32_t& value) + { + return sizeof(uint32_t); + } +}; + +/* + * Helper routines for serializing lists of arguments. + */ + +/* + * Given a list of arguments , returns the total size of + * the buffer required to fully serialize the list of arguments. + */ +template<class Head, class... Tail> +size_t SerializedSize(Head head, Tail... tail) +{ + return EventSerializationTraits<Head>::SerializedSize(head) + SerializedSize(tail...); +} + +template<class Head> +size_t SerializedSize(Head head) +{ + return EventSerializationTraits<Head>::SerializedSize(head); +} + +/* + * Given a list of arguments and a list of actual parameters, serialize + * the arguments into the buffer that's given to us. + */ +template<class Head, class... Tail> +void Serialize(uint8_t** buf, Head head, Tail... tail) +{ + EventSerializationTraits<Head>::Serialize(head, buf); + Serialize(buf, tail...); +} + +template<class Head> +void Serialize(uint8_t** buf, Head head) +{ + EventSerializationTraits<Head>::Serialize(head, buf); +} + +} // namespace gc_event + +#endif // __GCEVENT_SERIALIZERS_H__ + diff --git a/src/gc/gcevents.h b/src/gc/gcevents.h index cfc1571418..94087d7171 100644 --- a/src/gc/gcevents.h +++ b/src/gc/gcevents.h @@ -6,7 +6,7 @@ #endif // KNOWN_EVENT #ifndef DYNAMIC_EVENT - #define DYNAMIC_EVENT(name, provider, level, keyword, ...) + #define DYNAMIC_EVENT(name, level, keyword, ...) #endif // DYNAMIC_EVENT #undef KNOWN_EVENT diff --git a/src/gc/gceventstatus.h b/src/gc/gceventstatus.h index 1d992fcda3..95ed337475 100644 --- a/src/gc/gceventstatus.h +++ b/src/gc/gceventstatus.h @@ -27,6 +27,7 @@ #include "common.h" #include "gcenv.h" #include "gc.h" +#include "gcevent_serializers.h" // Uncomment this define to print out event state changes to standard error. // #define TRACE_GC_EVENT_STATE 1 @@ -187,23 +188,70 @@ private: GCEventStatus() = delete; }; -class GCDynamicEvent +/* + * FireDynamicEvent is a variadic function that fires a dynamic event with the + * given name and event payload. This function serializes the arguments into + * a binary payload that is then passed to IGCToCLREventSink::FireDynamicEvent. + */ +template<typename... EventArgument> +void FireDynamicEvent(const char* name, EventArgument... arguments) { - /* TODO(segilles) - Not Yet Implemented */ + size_t size = gc_event::SerializedSize(arguments...); + if (size > UINT32_MAX) + { + // ETW can't handle anything this big. + // we shouldn't be firing events that big anyway. + return; + } + + uint8_t* buf = new (nothrow) uint8_t[size]; + if (!buf) + { + // best effort - if we're OOM, don't bother with the event. + return; + } + + memset(buf, 0, size); + uint8_t* cursor = buf; + gc_event::Serialize(&cursor, arguments...); + IGCToCLREventSink* sink = GCToEEInterface::EventSink(); + assert(sink != nullptr); + sink->FireDynamicEvent(name, buf, static_cast<uint32_t>(size)); + delete[] buf; }; +/* + * In order to provide a consistent interface between known and dynamic events, + * two wrapper functions are generated for each known and dynamic event: + * GCEventEnabled##name() - Returns true if the event is enabled, false otherwise. + * GCEventFire##name(...) - Fires the event, with the event payload consisting of + * the arguments to the function. + * + * Because the schema of dynamic events comes from the DYNAMIC_EVENT xmacro, we use + * the arguments vector as the argument list to `FireDynamicEvent`, which will traverse + * the list of arguments and call `IGCToCLREventSink::FireDynamicEvent` with a serialized + * payload. Known events will delegate to IGCToCLREventSink::Fire##name. + */ #if FEATURE_EVENT_TRACE -#define KNOWN_EVENT(name, _provider, _level, _keyword) \ - inline bool GCEventEnabled##name() { return GCEventStatus::IsEnabled(_provider, _level, _keyword); } +#define KNOWN_EVENT(name, provider, level, keyword) \ + inline bool GCEventEnabled##name() { return GCEventStatus::IsEnabled(provider, keyword, level); } \ + template<typename... EventActualArgument> \ + inline void GCEventFire##name(EventActualArgument... arguments) \ + { \ + IGCToCLREventSink* sink = GCToEEInterface::EventSink(); \ + assert(sink != nullptr); \ + sink->Fire##name(arguments...); \ + } + +#define DYNAMIC_EVENT(name, level, keyword, ...) \ + inline bool GCEventEnabled##name() { return GCEventStatus::IsEnabled(GCEventProvider_Default, keyword, level); } \ + template<typename... EventActualArgument> \ + inline void GCEventFire##name(EventActualArgument... arguments) { FireDynamicEvent<__VA_ARGS__>(#name, arguments...); } + #include "gcevents.h" #define EVENT_ENABLED(name) GCEventEnabled##name() -#define FIRE_EVENT(name, ...) \ - do { \ - IGCToCLREventSink* sink = GCToEEInterface::EventSink(); \ - assert(sink != nullptr); \ - sink->Fire##name(__VA_ARGS__); \ - } while(0) +#define FIRE_EVENT(name, ...) GCEventFire##name(__VA_ARGS__) #else #define EVENT_ENABLED(name) false #define FIRE_EVENT(name, ...) 0 diff --git a/src/gc/gcinterface.ee.h b/src/gc/gcinterface.ee.h index f765362676..657e16ebb1 100644 --- a/src/gc/gcinterface.ee.h +++ b/src/gc/gcinterface.ee.h @@ -16,7 +16,15 @@ // to the EE. ([LOCALGC TODO dynamic event implementation]) class IGCToCLREventSink { - /* [LOCALGC TODO] This will be filled with events as they get ported */ +public: + // Fires a dynamic event with the given event name and payload. Dynamic + // events are not known to the EE and are fired as an unschematized event + // to the underlying eventing implementation. + virtual + void FireDynamicEvent( + const char* eventName, + void* payload, + uint32_t payloadSize) = 0; }; // This interface provides the interface that the GC will use to speak to the rest diff --git a/src/gc/gcsvr.cpp b/src/gc/gcsvr.cpp index db67aa3eef..e85555c77f 100644 --- a/src/gc/gcsvr.cpp +++ b/src/gc/gcsvr.cpp @@ -17,6 +17,7 @@ #include "handletable.h" #include "handletable.inl" #include "gcenv.inl" +#include "gceventstatus.h" #define SERVER_GC 1 diff --git a/src/gc/gcwks.cpp b/src/gc/gcwks.cpp index 335755608d..ad66dd6b34 100644 --- a/src/gc/gcwks.cpp +++ b/src/gc/gcwks.cpp @@ -15,6 +15,7 @@ #include "handletable.h" #include "handletable.inl" #include "gcenv.inl" +#include "gceventstatus.h" #ifdef SERVER_GC #undef SERVER_GC |