summaryrefslogtreecommitdiffstats
path: root/tools/profiler/public/ETWTools.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/profiler/public/ETWTools.h')
-rw-r--r--tools/profiler/public/ETWTools.h207
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,