Bug 2052468 - Treat an undeclared PayloadFields in a BaseMarkerType subclass as empty r=canova,profiler-reviewers

BaseMarkerType now provides an empty default PayloadFields member, so marker
types with no payload no longer need to declare PayloadFields (or an empty
StreamJSONMarkerData). The PayloadFieldsTuple deduction reuses the existing
MarkerHasPayloadFields trait to fall back to an empty argument list.

Migrate nsThread.cpp's LongTaskMarker to BaseMarkerType as the first consumer.

Differential Revision: https://phabricator.services.mozilla.com/D310299
This commit is contained in:
Damien Carver
2026-09-09 16:37:58 +00:00
committed by dcarver@mozilla.com
parent 8fb310698b
commit 5a96a6d6eb
2 changed files with 32 additions and 26 deletions
@@ -1063,6 +1063,14 @@ class MarkerSchema {
std::vector<GraphData> mGraphs;
};
// Check if T::PayloadFields exists and if it is not empty
template <typename T, typename = void>
struct MarkerHasPayloadFields : std::false_type {};
template <typename T>
struct MarkerHasPayloadFields<
T, std::void_t<decltype(T::PayloadFields),
decltype(std::size(T::PayloadFields))>> : std::true_type {};
namespace detail {
// GCC doesn't allow this to live inside the class.
// Class template so that partial specializations (e.g. for ProfilerString16View
@@ -1196,20 +1204,22 @@ template <typename T, size_t... Is>
auto PayloadFieldsTupleHelper(std::index_sequence<Is...>) -> std::tuple<
typename InputTypeToCpp<T::PayloadFields[Is].InputTy>::Type...>;
// A marker type with no (or empty) `PayloadFields` has no payload arguments.
template <typename T, bool = MarkerHasPayloadFields<T>::value>
struct PayloadFieldsTupleImpl {
using Type = std::tuple<>;
};
template <typename T>
using PayloadFieldsTuple = decltype(PayloadFieldsTupleHelper<T>(
std::make_index_sequence<std::size(T::PayloadFields)>{}));
struct PayloadFieldsTupleImpl<T, true> {
using Type = decltype(PayloadFieldsTupleHelper<T>(
std::make_index_sequence<std::size(T::PayloadFields)>{}));
};
template <typename T>
using PayloadFieldsTuple = typename PayloadFieldsTupleImpl<T>::Type;
} // namespace detail
// Check if T::PayloadFields exists and if it is not empty
template <typename T, typename = void>
struct MarkerHasPayloadFields : std::false_type {};
template <typename T>
struct MarkerHasPayloadFields<
T, std::void_t<decltype(T::PayloadFields),
decltype(std::size(T::PayloadFields))>> : std::true_type {};
// Check if T::TranslateMarkerInputToSchema exists
template <typename T, typename = void>
struct MarkerHasTranslator : std::false_type {};
@@ -1245,6 +1255,8 @@ struct BaseMarkerType {
static constexpr MarkerSchema::ETWMarkerGroup Group =
MarkerSchema::ETWMarkerGroup::Generic;
static constexpr MarkerSchema::PayloadField PayloadFields[0] = {};
static MarkerSchema MarkerTypeDisplay() {
using MS = MarkerSchema;
MS schema{T::Locations, std::size(T::Locations)};
+10 -16
View File
@@ -1500,6 +1500,16 @@ void PerformanceCounterState::RunnableDidRun(const nsCString& aName,
}
}
struct LongTaskMarker : public BaseMarkerType<LongTaskMarker> {
static constexpr const char* Name = "MainThreadLongTask";
static constexpr bool StoreName = true;
using MS = MarkerSchema;
static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
MS::Location::MarkerTable};
};
void PerformanceCounterState::MaybeReportAccumulatedTime(const nsCString& aName,
TimeStamp aNow) {
MOZ_ASSERT(mCurrentTimeSliceStart,
@@ -1525,22 +1535,6 @@ void PerformanceCounterState::MaybeReportAccumulatedTime(const nsCString& aName,
mLastLongTaskEnd = aNow;
if (profiler_thread_is_being_profiled_for_markers()) {
struct LongTaskMarker {
static constexpr Span<const char> MarkerTypeName() {
return MakeStringSpan("MainThreadLongTask");
}
static void StreamJSONMarkerData(
baseprofiler::SpliceableJSONWriter& aWriter) {
aWriter.StringProperty("category", "LongTask");
}
static MarkerSchema MarkerTypeDisplay() {
using MS = MarkerSchema;
MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
schema.AddKeyLabelFormat("category", "Type", MS::Format::String);
return schema;
}
};
profiler_add_marker(mCurrentRunnableIsIdleRunnable
? ProfilerString8View("LongIdleTask")
: ProfilerString8View("LongTask"),