зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1884213 - Part 2: Create generalized storage option for the marker names passed as arguments. r=mstange,profiler-reviewers
This allows for individual Marker Types to specify that they wish to have the names passed in profiler_add_marker stored as a field in ETW. This also converts simple marker types to use this in order to simplify the code. Differential Revision: https://phabricator.services.mozilla.com/D203983
This commit is contained in:
Родитель
f597d2936f
Коммит
60fc6e2727
|
@ -1018,6 +1018,10 @@ struct BaseMarkerType {
|
|||
static constexpr const char* TableLabel = nullptr;
|
||||
static constexpr const char* TooltipLabel = nullptr;
|
||||
|
||||
// This indicates whether this marker type wants the names passed to the
|
||||
// individual marker calls stores along with the marker.
|
||||
static constexpr bool StoreName = false;
|
||||
|
||||
static constexpr MarkerSchema::ETWMarkerGroup Group =
|
||||
MarkerSchema::ETWMarkerGroup::Generic;
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ A marker type must have a unique name, it is used to keep track of the type of
|
|||
markers in the profiler storage, and to identify them uniquely on profiler.firefox.com.
|
||||
(It does not need to be the same as the ``struct``'s name.)
|
||||
|
||||
This name is defined in a special static data member ``Name``:
|
||||
This type name is defined in a special static data member ``Name``:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
|
@ -333,6 +333,14 @@ In addition you must add a description of your marker in a special static data m
|
|||
// …
|
||||
static constexpr const char* Description = "This is my marker!";
|
||||
|
||||
If you expect users to be passing unique names for individual instances of the marker,
|
||||
you may want to add the following to ensure those names get stored when using ETW:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// …
|
||||
static constexpr bool StoreName = true;
|
||||
|
||||
Marker Type Data
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -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,9 +31,16 @@ 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"},
|
||||
|
@ -43,19 +52,25 @@ struct BaseMarkerDescription {
|
|||
|
||||
// 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;
|
||||
|
@ -123,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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -228,8 +251,7 @@ void CreateDataDescForPayload(PayloadBuffer& aBuffer,
|
|||
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 {};
|
||||
|
@ -273,32 +295,16 @@ static inline void StoreBaseEventDataDesc(
|
|||
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, 8> descriptors = {};
|
||||
|
||||
// This is storage space allocated on the stack for POD values.
|
||||
BaseEventStorage dataStorage = {};
|
||||
|
||||
StoreBaseEventDataDesc(dataStorage, descriptors.data(), aCategory,
|
||||
std::move(aOptions));
|
||||
|
||||
EventDataDescCreate(&descriptors[7], 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>
|
||||
|
@ -310,7 +316,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;
|
||||
|
@ -321,9 +327,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.
|
||||
|
@ -333,23 +337,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,
|
||||
|
@ -381,9 +395,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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче