summaryrefslogtreecommitdiffstats
path: root/tools/profiler/public/ProfilerMarkers.h
diff options
context:
space:
mode:
Diffstat (limited to 'tools/profiler/public/ProfilerMarkers.h')
-rw-r--r--tools/profiler/public/ProfilerMarkers.h355
1 files changed, 355 insertions, 0 deletions
diff --git a/tools/profiler/public/ProfilerMarkers.h b/tools/profiler/public/ProfilerMarkers.h
new file mode 100644
index 0000000000..ca53c3f189
--- /dev/null
+++ b/tools/profiler/public/ProfilerMarkers.h
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Markers are useful to delimit something important happening such as the first
+// paint. Unlike labels, which are only recorded in the profile buffer if a
+// sample is collected while the label is on the label stack, markers will
+// always be recorded in the profile buffer.
+//
+// This header contains definitions necessary to add markers to the Gecko
+// Profiler buffer.
+//
+// It #include's "mozilla/BaseProfilerMarkers.h", see that header for base
+// definitions necessary to create marker types.
+//
+// If common marker types are needed, #include "ProfilerMarkerTypes.h" instead.
+//
+// But if you want to create your own marker type locally, you can #include this
+// header only; look at ProfilerMarkerTypes.h for examples of how to define
+// types.
+//
+// To then record markers:
+// - Use `baseprofiler::AddMarker(...)` from mozglue or other libraries that are
+// outside of xul, especially if they may happen outside of xpcom's lifetime
+// (typically startup, shutdown, or tests).
+// - Otherwise #include "ProfilerMarkers.h" instead, and use
+// `profiler_add_marker(...)`.
+// See these functions for more details.
+
+#ifndef ProfilerMarkers_h
+#define ProfilerMarkers_h
+
+#include "mozilla/BaseProfilerMarkers.h"
+#include "mozilla/ProfilerMarkersDetail.h"
+#include "mozilla/ProfilerLabels.h"
+#include "nsJSUtils.h" // for nsJSUtils::GetCurrentlyRunningCodeInnerWindowID
+
+class nsIDocShell;
+
+namespace geckoprofiler::markers::detail {
+// Please do not use anything from the detail namespace outside the profiler.
+
+#ifdef MOZ_GECKO_PROFILER
+mozilla::Maybe<uint64_t> profiler_get_inner_window_id_from_docshell(
+ nsIDocShell* aDocshell);
+#else
+inline mozilla::Maybe<uint64_t> profiler_get_inner_window_id_from_docshell(
+ nsIDocShell* aDocshell) {
+ return mozilla::Nothing();
+}
+#endif // MOZ_GECKO_PROFILER
+
+} // namespace geckoprofiler::markers::detail
+
+// This is a helper function to get the Inner Window ID from DocShell but it's
+// not a recommended method to get it and it's not encouraged to use this
+// function. If there is a computed inner window ID, `window`, or `Document`
+// available in the call site, please use them. Use this function as a last
+// resort.
+inline mozilla::MarkerInnerWindowId MarkerInnerWindowIdFromDocShell(
+ nsIDocShell* aDocshell) {
+ mozilla::Maybe<uint64_t> id = geckoprofiler::markers::detail::
+ profiler_get_inner_window_id_from_docshell(aDocshell);
+ if (!id) {
+ return mozilla::MarkerInnerWindowId::NoId();
+ }
+ return mozilla::MarkerInnerWindowId(*id);
+}
+
+// This is a helper function to get the Inner Window ID from a JS Context but
+// it's not a recommended method to get it and it's not encouraged to use this
+// function. If there is a computed inner window ID, `window`, or `Document`
+// available in the call site, please use them. Use this function as a last
+// resort.
+inline mozilla::MarkerInnerWindowId MarkerInnerWindowIdFromJSContext(
+ JSContext* aContext) {
+ return mozilla::MarkerInnerWindowId(
+ nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(aContext));
+}
+
+// Bring category names from Base Profiler into the geckoprofiler::category
+// namespace, for consistency with other Gecko Profiler identifiers.
+namespace geckoprofiler::category {
+using namespace ::mozilla::baseprofiler::category;
+}
+
+#ifdef MOZ_GECKO_PROFILER
+// Forward-declaration. TODO: Move to more common header, see bug 1681416.
+bool profiler_capture_backtrace_into(
+ mozilla::ProfileChunkedBuffer& aChunkedBuffer,
+ mozilla::StackCaptureOptions aCaptureOptions);
+
+// Add a marker to a given buffer. `AddMarker()` and related macros should be
+// used in most cases, see below for more information about them and the
+// paramters; This function may be useful when markers need to be recorded in a
+// local buffer outside of the main profiler buffer.
+template <typename MarkerType, typename... PayloadArguments>
+mozilla::ProfileBufferBlockIndex AddMarkerToBuffer(
+ mozilla::ProfileChunkedBuffer& aBuffer,
+ const mozilla::ProfilerString8View& aName,
+ const mozilla::MarkerCategory& aCategory, mozilla::MarkerOptions&& aOptions,
+ MarkerType aMarkerType, const PayloadArguments&... aPayloadArguments) {
+ AUTO_PROFILER_LABEL("AddMarkerToBuffer", PROFILER);
+ mozilla::Unused << aMarkerType; // Only the empty object type is useful.
+ return mozilla::base_profiler_markers_detail::AddMarkerToBuffer<MarkerType>(
+ aBuffer, aName, aCategory, std::move(aOptions),
+ profiler_active_without_feature(ProfilerFeature::NoMarkerStacks)
+ ? ::profiler_capture_backtrace_into
+ : nullptr,
+ aPayloadArguments...);
+}
+
+// Add a marker (without payload) to a given buffer.
+inline mozilla::ProfileBufferBlockIndex AddMarkerToBuffer(
+ mozilla::ProfileChunkedBuffer& aBuffer,
+ const mozilla::ProfilerString8View& aName,
+ const mozilla::MarkerCategory& aCategory,
+ mozilla::MarkerOptions&& aOptions = {}) {
+ return AddMarkerToBuffer(aBuffer, aName, aCategory, std::move(aOptions),
+ mozilla::baseprofiler::markers::NoPayload{});
+}
+#endif
+
+[[nodiscard]] inline bool profiler_thread_is_being_profiled_for_markers() {
+ return profiler_thread_is_being_profiled(ThreadProfilingFeatures::Markers);
+}
+
+[[nodiscard]] inline bool profiler_thread_is_being_profiled_for_markers(
+ const ProfilerThreadId& aThreadId) {
+ return profiler_thread_is_being_profiled(aThreadId,
+ ThreadProfilingFeatures::Markers);
+}
+
+// Add a marker to the Gecko Profiler buffer.
+// - aName: Main name of this marker.
+// - aCategory: Category for this marker.
+// - aOptions: Optional settings (such as timing, inner window id,
+// backtrace...), see `MarkerOptions` for details.
+// - aMarkerType: Empty object that specifies the type of marker.
+// - aPayloadArguments: Arguments expected by this marker type's
+// ` StreamJSONMarkerData` function.
+template <typename MarkerType, typename... PayloadArguments>
+mozilla::ProfileBufferBlockIndex profiler_add_marker(
+ const mozilla::ProfilerString8View& aName,
+ const mozilla::MarkerCategory& aCategory, mozilla::MarkerOptions&& aOptions,
+ MarkerType aMarkerType, const PayloadArguments&... aPayloadArguments) {
+#ifndef MOZ_GECKO_PROFILER
+ return {};
+#else
+ if (!profiler_thread_is_being_profiled_for_markers(
+ aOptions.ThreadId().ThreadId())) {
+ return {};
+ }
+ AUTO_PROFILER_LABEL("profiler_add_marker", PROFILER);
+ return ::AddMarkerToBuffer(profiler_get_core_buffer(), aName, aCategory,
+ std::move(aOptions), aMarkerType,
+ aPayloadArguments...);
+#endif
+}
+
+// Add a marker (without payload) to the Gecko Profiler buffer.
+inline mozilla::ProfileBufferBlockIndex profiler_add_marker(
+ const mozilla::ProfilerString8View& aName,
+ const mozilla::MarkerCategory& aCategory,
+ mozilla::MarkerOptions&& aOptions = {}) {
+ return profiler_add_marker(aName, aCategory, std::move(aOptions),
+ mozilla::baseprofiler::markers::NoPayload{});
+}
+
+// Same as `profiler_add_marker()` (without payload). This macro is safe to use
+// even if MOZ_GECKO_PROFILER is not #defined.
+#define PROFILER_MARKER_UNTYPED(markerName, categoryName, ...) \
+ do { \
+ AUTO_PROFILER_STATS(PROFILER_MARKER_UNTYPED); \
+ ::profiler_add_marker(markerName, ::geckoprofiler::category::categoryName, \
+ ##__VA_ARGS__); \
+ } while (false)
+
+// Same as `profiler_add_marker()` (with payload). This macro is safe to use
+// even if MOZ_GECKO_PROFILER is not #defined.
+#define PROFILER_MARKER(markerName, categoryName, options, MarkerType, ...) \
+ do { \
+ AUTO_PROFILER_STATS(PROFILER_MARKER_with_##MarkerType); \
+ ::profiler_add_marker(markerName, ::geckoprofiler::category::categoryName, \
+ options, ::geckoprofiler::markers::MarkerType{}, \
+ ##__VA_ARGS__); \
+ } while (false)
+
+namespace geckoprofiler::markers {
+// Most common marker types. Others are in ProfilerMarkerTypes.h.
+using TextMarker = ::mozilla::baseprofiler::markers::TextMarker;
+using Tracing = mozilla::baseprofiler::markers::Tracing;
+} // namespace geckoprofiler::markers
+
+// Add a text marker. This macro is safe to use even if MOZ_GECKO_PROFILER is
+// not #defined.
+#define PROFILER_MARKER_TEXT(markerName, categoryName, options, text) \
+ do { \
+ AUTO_PROFILER_STATS(PROFILER_MARKER_TEXT); \
+ ::profiler_add_marker(markerName, ::geckoprofiler::category::categoryName, \
+ options, ::geckoprofiler::markers::TextMarker{}, \
+ text); \
+ } while (false)
+
+// RAII object that adds a PROFILER_MARKER_TEXT when destroyed; the marker's
+// timing will be the interval from construction (unless an instant or start
+// time is already specified in the provided options) until destruction.
+class MOZ_RAII AutoProfilerTextMarker {
+ public:
+ AutoProfilerTextMarker(const char* aMarkerName,
+ const mozilla::MarkerCategory& aCategory,
+ mozilla::MarkerOptions&& aOptions,
+ const nsACString& aText)
+ : mMarkerName(aMarkerName),
+ mCategory(aCategory),
+ mOptions(std::move(aOptions)),
+ mText(aText) {
+ MOZ_ASSERT(mOptions.Timing().EndTime().IsNull(),
+ "AutoProfilerTextMarker options shouldn't have an end time");
+ if (profiler_is_active_and_unpaused() &&
+ mOptions.Timing().StartTime().IsNull()) {
+ mOptions.Set(mozilla::MarkerTiming::InstantNow());
+ }
+ }
+
+ ~AutoProfilerTextMarker() {
+ if (profiler_is_active_and_unpaused()) {
+ AUTO_PROFILER_LABEL("TextMarker", PROFILER);
+ mOptions.TimingRef().SetIntervalEnd();
+ AUTO_PROFILER_STATS(AUTO_PROFILER_MARKER_TEXT);
+ profiler_add_marker(
+ mozilla::ProfilerString8View::WrapNullTerminatedString(mMarkerName),
+ mCategory, std::move(mOptions), geckoprofiler::markers::TextMarker{},
+ mText);
+ }
+ }
+
+ protected:
+ const char* mMarkerName;
+ mozilla::MarkerCategory mCategory;
+ mozilla::MarkerOptions mOptions;
+ nsCString mText;
+};
+
+// Creates an AutoProfilerTextMarker RAII object. This macro is safe to use
+// even if MOZ_GECKO_PROFILER is not #defined.
+#define AUTO_PROFILER_MARKER_TEXT(markerName, categoryName, options, text) \
+ AutoProfilerTextMarker PROFILER_RAII( \
+ markerName, ::mozilla::baseprofiler::category::categoryName, options, \
+ text)
+
+class MOZ_RAII AutoProfilerTracing {
+ public:
+ AutoProfilerTracing(const char* aCategoryString, const char* aMarkerName,
+ mozilla::MarkerCategory aCategoryPair,
+ const mozilla::Maybe<uint64_t>& aInnerWindowID)
+ : mCategoryString(aCategoryString),
+ mMarkerName(aMarkerName),
+ mCategoryPair(aCategoryPair),
+ mInnerWindowID(aInnerWindowID) {
+ profiler_add_marker(
+ mozilla::ProfilerString8View::WrapNullTerminatedString(mMarkerName),
+ mCategoryPair,
+ {mozilla::MarkerTiming::IntervalStart(),
+ mozilla::MarkerInnerWindowId(mInnerWindowID)},
+ geckoprofiler::markers::Tracing{},
+ mozilla::ProfilerString8View::WrapNullTerminatedString(
+ mCategoryString));
+ }
+
+ AutoProfilerTracing(
+ const char* aCategoryString, const char* aMarkerName,
+ mozilla::MarkerCategory aCategoryPair,
+ mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> aBacktrace,
+ const mozilla::Maybe<uint64_t>& aInnerWindowID)
+ : mCategoryString(aCategoryString),
+ mMarkerName(aMarkerName),
+ mCategoryPair(aCategoryPair),
+ mInnerWindowID(aInnerWindowID) {
+ profiler_add_marker(
+ mozilla::ProfilerString8View::WrapNullTerminatedString(mMarkerName),
+ mCategoryPair,
+ {mozilla::MarkerTiming::IntervalStart(),
+ mozilla::MarkerInnerWindowId(mInnerWindowID),
+ mozilla::MarkerStack::TakeBacktrace(std::move(aBacktrace))},
+ geckoprofiler::markers::Tracing{},
+ mozilla::ProfilerString8View::WrapNullTerminatedString(
+ mCategoryString));
+ }
+
+ ~AutoProfilerTracing() {
+ profiler_add_marker(
+ mozilla::ProfilerString8View::WrapNullTerminatedString(mMarkerName),
+ mCategoryPair,
+ {mozilla::MarkerTiming::IntervalEnd(),
+ mozilla::MarkerInnerWindowId(mInnerWindowID)},
+ geckoprofiler::markers::Tracing{},
+ mozilla::ProfilerString8View::WrapNullTerminatedString(
+ mCategoryString));
+ }
+
+ protected:
+ const char* mCategoryString;
+ const char* mMarkerName;
+ const mozilla::MarkerCategory mCategoryPair;
+ const mozilla::Maybe<uint64_t> mInnerWindowID;
+};
+
+// Adds a START/END pair of tracing markers.
+#define AUTO_PROFILER_TRACING_MARKER(categoryString, markerName, categoryPair) \
+ AutoProfilerTracing PROFILER_RAII(categoryString, markerName, \
+ geckoprofiler::category::categoryPair, \
+ mozilla::Nothing())
+#define AUTO_PROFILER_TRACING_MARKER_INNERWINDOWID( \
+ categoryString, markerName, categoryPair, innerWindowId) \
+ AutoProfilerTracing PROFILER_RAII(categoryString, markerName, \
+ geckoprofiler::category::categoryPair, \
+ mozilla::Some(innerWindowId))
+#define AUTO_PROFILER_TRACING_MARKER_DOCSHELL(categoryString, markerName, \
+ categoryPair, docShell) \
+ AutoProfilerTracing PROFILER_RAII( \
+ categoryString, markerName, geckoprofiler::category::categoryPair, \
+ geckoprofiler::markers::detail:: \
+ profiler_get_inner_window_id_from_docshell(docShell))
+
+#ifdef MOZ_GECKO_PROFILER
+extern template mozilla::ProfileBufferBlockIndex AddMarkerToBuffer(
+ mozilla::ProfileChunkedBuffer&, const mozilla::ProfilerString8View&,
+ const mozilla::MarkerCategory&, mozilla::MarkerOptions&&,
+ mozilla::baseprofiler::markers::NoPayload);
+
+extern template mozilla::ProfileBufferBlockIndex AddMarkerToBuffer(
+ mozilla::ProfileChunkedBuffer&, const mozilla::ProfilerString8View&,
+ const mozilla::MarkerCategory&, mozilla::MarkerOptions&&,
+ mozilla::baseprofiler::markers::TextMarker, const std::string&);
+
+extern template mozilla::ProfileBufferBlockIndex profiler_add_marker(
+ const mozilla::ProfilerString8View&, const mozilla::MarkerCategory&,
+ mozilla::MarkerOptions&&, mozilla::baseprofiler::markers::TextMarker,
+ const std::string&);
+
+extern template mozilla::ProfileBufferBlockIndex profiler_add_marker(
+ const mozilla::ProfilerString8View&, const mozilla::MarkerCategory&,
+ mozilla::MarkerOptions&&, mozilla::baseprofiler::markers::TextMarker,
+ const nsCString&);
+
+extern template mozilla::ProfileBufferBlockIndex profiler_add_marker(
+ const mozilla::ProfilerString8View&, const mozilla::MarkerCategory&,
+ mozilla::MarkerOptions&&, mozilla::baseprofiler::markers::Tracing,
+ const mozilla::ProfilerString8View&);
+#endif // MOZ_GECKO_PROFILER
+
+#endif // ProfilerMarkers_h