diff options
Diffstat (limited to 'tools/profiler/public/ETWTools.h')
-rw-r--r-- | tools/profiler/public/ETWTools.h | 207 |
1 files changed, 117 insertions, 90 deletions
diff --git a/tools/profiler/public/ETWTools.h b/tools/profiler/public/ETWTools.h index a1d986a6fd..cbd73004ba 100644 --- a/tools/profiler/public/ETWTools.h +++ b/tools/profiler/public/ETWTools.h @@ -22,6 +22,8 @@ namespace ETW { extern std::atomic<ULONGLONG> gETWCollectionMask; +constexpr const char* kNameKey = "MarkerName"; + // Forward-declare the g_hMyComponentProvider variable that you will use for // tracing in this component TRACELOGGING_DECLARE_PROVIDER(kFirefoxTraceLoggingProvider); @@ -29,32 +31,46 @@ TRACELOGGING_DECLARE_PROVIDER(kFirefoxTraceLoggingProvider); void Init(); void Shutdown(); +template <typename T, typename = void> +struct MarkerHasPayload : std::false_type {}; +template <typename T> +struct MarkerHasPayload<T, std::void_t<decltype(T::PayloadFields)>> + : std::true_type {}; + // This describes the base fields for all markers (information extracted from // MarkerOptions. struct BaseMarkerDescription { + static constexpr bool StoreName = false; using MS = mozilla::MarkerSchema; static constexpr MS::PayloadField PayloadFields[] = { {"StartTime", MS::InputType::TimeStamp, "Start Time"}, {"EndTime", MS::InputType::TimeStamp, "End Time"}, + {"Phase", MS::InputType::Uint8, "Phase"}, {"InnerWindowId", MS::InputType::Uint64, "Inner Window ID"}, {"CategoryPair", MS::InputType::Uint32, "Category Pair"}}; }; // This is the MarkerType object for markers with no statically declared type, // their name is written dynamically. -struct SimpleMarkerType { +struct SimpleMarkerType : public mozilla::BaseMarkerType<SimpleMarkerType> { using MS = mozilla::MarkerSchema; + static constexpr const char* Name = "SimpleMarker"; - static constexpr MS::PayloadField PayloadFields[] = { - {"MarkerName", MS::InputType::CString, "Simple Marker Name"}}; + static constexpr bool StoreName = true; }; // This gets the space required in the Tlg static struct to pack the fields. template <typename T> constexpr std::size_t GetPackingSpace() { size_t length = 0; - for (size_t i = 0; i < std::size(T::PayloadFields); i++) { - length += std::string_view{T::PayloadFields[i].Key}.size() + 1; + if constexpr (MarkerHasPayload<T>::value) { + for (size_t i = 0; i < std::size(T::PayloadFields); i++) { + length += std::string_view{T::PayloadFields[i].Key}.size() + 1; + length += sizeof(uint8_t); + } + } + if (T::StoreName) { + length += std::string_view{kNameKey}.size() + 1; length += sizeof(uint8_t); } return length; @@ -65,6 +81,7 @@ constexpr uint8_t GetTlgInputType(mozilla::MarkerSchema::InputType aInput) { using InputType = mozilla::MarkerSchema::InputType; switch (aInput) { case InputType::Boolean: + case InputType::Uint8: return TlgInUINT8; case InputType::Uint32: return TlgInUINT32; @@ -121,12 +138,20 @@ struct StaticMetaData { fieldStorage[pos++] = GetTlgInputType(BaseMarkerDescription::PayloadFields[i].InputTy); } - for (uint32_t i = 0; i < std::size(T::PayloadFields); i++) { - for (size_t c = 0; - c < std::string_view{T::PayloadFields[i].Key}.size() + 1; c++) { - fieldStorage[pos++] = T::PayloadFields[i].Key[c]; + if (T::StoreName) { + for (size_t c = 0; c < std::string_view{kNameKey}.size() + 1; c++) { + fieldStorage[pos++] = kNameKey[c]; + } + fieldStorage[pos++] = TlgInANSISTRING; + } + if constexpr (MarkerHasPayload<T>::value) { + for (uint32_t i = 0; i < std::size(T::PayloadFields); i++) { + for (size_t c = 0; + c < std::string_view{T::PayloadFields[i].Key}.size() + 1; c++) { + fieldStorage[pos++] = T::PayloadFields[i].Key[c]; + } + fieldStorage[pos++] = GetTlgInputType(T::PayloadFields[i].InputTy); } - fieldStorage[pos++] = GetTlgInputType(T::PayloadFields[i].InputTy); } } }; @@ -146,10 +171,11 @@ struct PayloadBuffer { // Theoretically we could probably avoid these assignments when passed a POD // variable we know is going to be alive but that would require some more // template magic. + template <typename T> -static void CreateDataDescForPayload(PayloadBuffer& aBuffer, - EVENT_DATA_DESCRIPTOR& aDescriptor, - const T& aPayload) { +void CreateDataDescForPayloadPOD(PayloadBuffer& aBuffer, + EVENT_DATA_DESCRIPTOR& aDescriptor, + const T& aPayload) { static_assert(std::is_pod<T>::value, "Writing a non-POD payload requires template specialization."); @@ -164,16 +190,22 @@ static void CreateDataDescForPayload(PayloadBuffer& aBuffer, EventDataDescCreate(&aDescriptor, storedValue, sizeof(T)); } -template <> -inline void CreateDataDescForPayload<mozilla::ProfilerString8View>( +static inline void CreateDataDescForPayloadNonPOD( PayloadBuffer& aBuffer, EVENT_DATA_DESCRIPTOR& aDescriptor, const mozilla::ProfilerString8View& aPayload) { EventDataDescCreate(&aDescriptor, aPayload.StringView().data(), aPayload.StringView().size() + 1); } -template <> -inline void CreateDataDescForPayload<mozilla::TimeStamp>( +template <typename T> +static inline void CreateDataDescForPayloadNonPOD( + PayloadBuffer& aBuffer, EVENT_DATA_DESCRIPTOR& aDescriptor, + const mozilla::detail::nsTStringRepr<T>& aPayload) { + EventDataDescCreate(&aDescriptor, aPayload.BeginReading(), + (aPayload.Length() + 1) * sizeof(T)); +} + +static inline void CreateDataDescForPayloadNonPOD( PayloadBuffer& aBuffer, EVENT_DATA_DESCRIPTOR& aDescriptor, const mozilla::TimeStamp& aPayload) { if (aPayload.RawQueryPerformanceCounterValue().isNothing()) { @@ -182,32 +214,25 @@ inline void CreateDataDescForPayload<mozilla::TimeStamp>( return; } - CreateDataDescForPayload(aBuffer, aDescriptor, - aPayload.RawQueryPerformanceCounterValue().value()); + CreateDataDescForPayloadPOD( + aBuffer, aDescriptor, aPayload.RawQueryPerformanceCounterValue().value()); } -template <> -inline void CreateDataDescForPayload<mozilla::TimeDuration>( +static inline void CreateDataDescForPayloadNonPOD( PayloadBuffer& aBuffer, EVENT_DATA_DESCRIPTOR& aDescriptor, const mozilla::TimeDuration& aPayload) { - CreateDataDescForPayload(aBuffer, aDescriptor, aPayload.ToMilliseconds()); + CreateDataDescForPayloadPOD(aBuffer, aDescriptor, aPayload.ToMilliseconds()); } -// For reasons that are beyond me if this isn't marked inline it generates an -// unused function warning despite being a template specialization. -template <typename T> -inline void CreateDataDescForPayload(PayloadBuffer& aBuffer, - EVENT_DATA_DESCRIPTOR& aDescriptor, - const nsTString<T>& aPayload) { - EventDataDescCreate(&aDescriptor, aPayload.BeginReading(), - (aPayload.Length() + 1) * sizeof(T)); -} template <typename T> -inline void CreateDataDescForPayload(PayloadBuffer& aBuffer, - EVENT_DATA_DESCRIPTOR& aDescriptor, - const nsTSubstring<T>& aPayload) { - EventDataDescCreate(&aDescriptor, aPayload.BeginReading(), - (aPayload.Length() + 1) * sizeof(T)); +static inline void CreateDataDescForPayload(PayloadBuffer& aBuffer, + EVENT_DATA_DESCRIPTOR& aDescriptor, + const T& aPayload) { + if constexpr (std::is_pod<T>::value) { + CreateDataDescForPayloadPOD(aBuffer, aDescriptor, aPayload); + } else { + CreateDataDescForPayloadNonPOD(aBuffer, aDescriptor, aPayload); + } } // Template specialization that writes out empty data descriptors for an empty @@ -223,11 +248,17 @@ void CreateDataDescForPayload(PayloadBuffer& aBuffer, } } +template <size_t N> +void CreateDataDescForPayload(PayloadBuffer& aBuffer, + EVENT_DATA_DESCRIPTOR& aDescriptor, + const char (&aPayload)[N]) { + EventDataDescCreate(&aDescriptor, aPayload, N + 1); +} + template <typename T, typename = void> struct MarkerSupportsETW : std::false_type {}; template <typename T> -struct MarkerSupportsETW<T, std::void_t<decltype(T::PayloadFields)>> - : std::true_type {}; +struct MarkerSupportsETW<T, std::void_t<decltype(T::Name)>> : std::true_type {}; template <typename T, typename = void> struct MarkerHasTranslator : std::false_type {}; @@ -239,6 +270,7 @@ struct MarkerHasTranslator< struct BaseEventStorage { uint64_t mStartTime; uint64_t mEndTime; + uint8_t mPhase; uint64_t mWindowID; uint32_t mCategoryPair; }; @@ -247,11 +279,16 @@ static inline void StoreBaseEventDataDesc( BaseEventStorage& aStorage, EVENT_DATA_DESCRIPTOR* aDescriptors, const mozilla::MarkerCategory& aCategory, const mozilla::MarkerOptions& aOptions) { - if (!aOptions.IsTimingUnspecified()) { + if (aOptions.IsTimingUnspecified()) { + aStorage.mStartTime = + mozilla::TimeStamp::Now().RawQueryPerformanceCounterValue().value(); + aStorage.mPhase = 0; + } else { aStorage.mStartTime = aOptions.Timing().StartTime().RawQueryPerformanceCounterValue().value(); aStorage.mEndTime = aOptions.Timing().EndTime().RawQueryPerformanceCounterValue().value(); + aStorage.mPhase = uint8_t(aOptions.Timing().MarkerPhase()); } if (!aOptions.InnerWindowId().IsUnspecified()) { aStorage.mWindowID = aOptions.InnerWindowId().Id(); @@ -259,37 +296,22 @@ static inline void StoreBaseEventDataDesc( aStorage.mCategoryPair = uint32_t(aCategory.CategoryPair()); EventDataDescCreate(&aDescriptors[2], &aStorage.mStartTime, sizeof(uint64_t)); EventDataDescCreate(&aDescriptors[3], &aStorage.mEndTime, sizeof(uint64_t)); - EventDataDescCreate(&aDescriptors[4], &aStorage.mWindowID, sizeof(uint64_t)); - EventDataDescCreate(&aDescriptors[5], &aStorage.mCategoryPair, + EventDataDescCreate(&aDescriptors[4], &aStorage.mPhase, sizeof(uint8_t)); + EventDataDescCreate(&aDescriptors[5], &aStorage.mWindowID, sizeof(uint64_t)); + EventDataDescCreate(&aDescriptors[6], &aStorage.mCategoryPair, sizeof(uint32_t)); } -// This is used for markers with no explicit type or markers which have not -// been converted to the updated schema yet. -static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, - const mozilla::MarkerCategory& aCategory, - const mozilla::MarkerOptions& aOptions = {}) { - if (!(gETWCollectionMask & - uint64_t(mozilla::MarkerSchema::ETWMarkerGroup::Generic))) { - return; +template <typename MarkerType> +constexpr size_t GetETWDescriptorCount() { + size_t count = 2 + std::size(BaseMarkerDescription::PayloadFields); + if (MarkerType::StoreName) { + count++; } - - static const __declspec(allocate(_tlgSegMetadataEvents)) __declspec( - align(1)) constexpr StaticMetaData<SimpleMarkerType> - staticData; - - std::array<EVENT_DATA_DESCRIPTOR, 7> descriptors = {}; - - // This is storage space allocated on the stack for POD values. - BaseEventStorage dataStorage = {}; - - StoreBaseEventDataDesc(dataStorage, descriptors.data(), aCategory, - std::move(aOptions)); - - EventDataDescCreate(&descriptors[6], aName.StringView().data(), - aName.StringView().size() + 1); - _tlgWriteTransfer(kFirefoxTraceLoggingProvider, &staticData.metaData.Channel, - NULL, NULL, descriptors.size(), descriptors.data()); + if constexpr (MarkerHasPayload<MarkerType>::value) { + count += std::size(MarkerType::PayloadFields); + } + return count; } template <typename MarkerType, typename... PayloadArguments> @@ -301,7 +323,7 @@ static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, // If our MarkerType has not been made to support ETW, emit only the base // event. Avoid attempting to compile the rest of the function. if constexpr (!MarkerSupportsETW<MarkerType>::value) { - return EmitETWMarker(aName, aCategory, aOptions); + return EmitETWMarker(aName, aCategory, aOptions, SimpleMarkerType{}); } else { if (!(gETWCollectionMask & uint64_t(MarkerType::Group))) { return; @@ -312,9 +334,7 @@ static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, staticData; // Allocate the exact amount of descriptors required by this event. - std::array<EVENT_DATA_DESCRIPTOR, - 2 + std::size(MarkerType::PayloadFields) + - std::size(BaseMarkerDescription::PayloadFields)> + std::array<EVENT_DATA_DESCRIPTOR, GetETWDescriptorCount<MarkerType>()> descriptors = {}; // Memory allocated on the stack for storing intermediate values. @@ -324,23 +344,33 @@ static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, StoreBaseEventDataDesc(dataStorage, descriptors.data(), aCategory, aOptions); - if constexpr (MarkerHasTranslator<MarkerType>::value) { - // When this function is implemented the arguments are passed back to the - // MarkerType object which is expected to call OutputMarkerSchema with - // the correct argument format. - buffer.mDescriptors = descriptors.data() + 2 + - std::size(BaseMarkerDescription::PayloadFields); - MarkerType::TranslateMarkerInputToSchema(&buffer, aPayloadArguments...); - } else { - const size_t argCount = sizeof...(PayloadArguments); - static_assert( - argCount == std::size(MarkerType::PayloadFields), - "Number and type of fields must be equal to number and type of " - "payload arguments. If this is not the case a " - "TranslateMarkerInputToSchema function must be defined."); - size_t i = 2 + std::size(BaseMarkerDescription::PayloadFields); - (CreateDataDescForPayload(buffer, descriptors[i++], aPayloadArguments), - ...); + if constexpr (MarkerType::StoreName) { + EventDataDescCreate(&descriptors[7], aName.StringView().data(), + aName.StringView().size() + 1); + } + + if constexpr (MarkerHasPayload<MarkerType>::value) { + if constexpr (MarkerHasTranslator<MarkerType>::value) { + // When this function is implemented the arguments are passed back to + // the MarkerType object which is expected to call OutputMarkerSchema + // with the correct argument format. + buffer.mDescriptors = descriptors.data() + 2 + + std::size(BaseMarkerDescription::PayloadFields) + + (MarkerType::StoreName ? 1 : 0); + + MarkerType::TranslateMarkerInputToSchema(&buffer, aPayloadArguments...); + } else { + const size_t argCount = sizeof...(PayloadArguments); + static_assert( + argCount == std::size(MarkerType::PayloadFields), + "Number and type of fields must be equal to number and type of " + "payload arguments. If this is not the case a " + "TranslateMarkerInputToSchema function must be defined."); + size_t i = 2 + std::size(BaseMarkerDescription::PayloadFields) + + (MarkerType::StoreName ? 1 : 0); + (CreateDataDescForPayload(buffer, descriptors[i++], aPayloadArguments), + ...); + } } _tlgWriteTransfer(kFirefoxTraceLoggingProvider, @@ -372,9 +402,6 @@ void OutputMarkerSchema(void* aContext, MarkerType aMarkerType, namespace ETW { static inline void Init() {} static inline void Shutdown() {} -static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, - const mozilla::MarkerCategory& aCategory, - const mozilla::MarkerOptions& aOptions = {}) {} template <typename MarkerType, typename... PayloadArguments> static inline void EmitETWMarker(const mozilla::ProfilerString8View& aName, const mozilla::MarkerCategory& aCategory, |