tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BaseProfilerMarkers.h (13889B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // Markers are useful to delimit something important happening such as the first
      8 // paint. Unlike labels, which are only recorded in the profile buffer if a
      9 // sample is collected while the label is on the label stack, markers will
     10 // always be recorded in the profile buffer.
     11 //
     12 // This header contains basic definitions necessary to create marker types, and
     13 // to add markers to the profiler buffers.
     14 //
     15 // If basic marker types are needed, #include
     16 // "mozilla/BaseProfilerMarkerTypes.h" instead.
     17 //
     18 // But if you want to create your own marker type locally, you can #include this
     19 // header only; look at mozilla/BaseProfilerMarkerTypes.h for examples of how to
     20 // define types, and mozilla/BaseProfilerMarkerPrerequisites.h for some
     21 // supporting types.
     22 //
     23 // To then record markers:
     24 // - Use `baseprofiler::AddMarker(...)` from  mozglue or other libraries that
     25 //   are outside of xul, especially if they may happen outside of xpcom's
     26 //   lifetime (typically startup, shutdown, or tests).
     27 // - Otherwise #include "ProfilerMarkers.h" instead, and use
     28 //   `profiler_add_marker(...)`.
     29 // See these functions for more details.
     30 
     31 #ifndef BaseProfilerMarkers_h
     32 #define BaseProfilerMarkers_h
     33 
     34 #include "mozilla/BaseProfilerMarkersDetail.h"
     35 #include "mozilla/BaseProfilerLabels.h"
     36 #include "mozilla/TimeStamp.h"
     37 
     38 #include <functional>
     39 #include <string>
     40 #include <utility>
     41 
     42 namespace mozilla::baseprofiler {
     43 
     44 #ifdef MOZ_GECKO_PROFILER
     45 // Forward-declaration. TODO: Move to more common header, see bug 1681416.
     46 MFBT_API bool profiler_capture_backtrace_into(
     47    ProfileChunkedBuffer& aChunkedBuffer, StackCaptureOptions aCaptureOptions);
     48 
     49 // Add a marker to a given buffer. `AddMarker()` and related macros should be
     50 // used in most cases, see below for more information about them and the
     51 // parameters; This function may be useful when markers need to be recorded in a
     52 // local buffer outside of the main profiler buffer.
     53 template <typename MarkerType, typename... PayloadArguments>
     54 ProfileBufferBlockIndex AddMarkerToBuffer(
     55    ProfileChunkedBuffer& aBuffer, const ProfilerString8View& aName,
     56    const MarkerCategory& aCategory, MarkerOptions&& aOptions,
     57    MarkerType aMarkerType, const PayloadArguments&... aPayloadArguments) {
     58  (void)aMarkerType;  // Only the empty object type is useful.
     59  AUTO_BASE_PROFILER_LABEL("baseprofiler::AddMarkerToBuffer", PROFILER);
     60  return base_profiler_markers_detail::AddMarkerToBuffer<MarkerType>(
     61      aBuffer, aName, aCategory, std::move(aOptions),
     62      // Do not capture a stack if the NoMarkerStacks feature is set.
     63      profiler_active_without_feature(ProfilerFeature::NoMarkerStacks)
     64          ? ::mozilla::baseprofiler::profiler_capture_backtrace_into
     65          : nullptr,
     66      aPayloadArguments...);
     67 }
     68 
     69 // Add a marker (without payload) to a given buffer.
     70 inline ProfileBufferBlockIndex AddMarkerToBuffer(
     71    ProfileChunkedBuffer& aBuffer, const ProfilerString8View& aName,
     72    const MarkerCategory& aCategory, MarkerOptions&& aOptions = {}) {
     73  return AddMarkerToBuffer(aBuffer, aName, aCategory, std::move(aOptions),
     74                           markers::NoPayload{});
     75 }
     76 #endif  // MOZ_GECKO_PROFILER
     77 
     78 // Add a marker to the Base Profiler buffer.
     79 // - aName: Main name of this marker.
     80 // - aCategory: Category for this marker.
     81 // - aOptions: Optional settings (such as timing, inner window id,
     82 //   backtrace...), see `MarkerOptions` for details.
     83 // - aMarkerType: Empty object that specifies the type of marker.
     84 // - aPayloadArguments: Arguments expected by this marker type's
     85 // ` StreamJSONMarkerData` function.
     86 template <typename MarkerType, typename... PayloadArguments>
     87 ProfileBufferBlockIndex AddMarker(
     88    const ProfilerString8View& aName, const MarkerCategory& aCategory,
     89    MarkerOptions&& aOptions, MarkerType aMarkerType,
     90    const PayloadArguments&... aPayloadArguments) {
     91 #ifndef MOZ_GECKO_PROFILER
     92  return {};
     93 #else
     94  // Record base markers whenever the core buffer is in session.
     95  // TODO: When profiler_thread_is_being_profiled becomes available from
     96  // mozglue, use it instead.
     97  ProfileChunkedBuffer& coreBuffer =
     98      ::mozilla::baseprofiler::profiler_get_core_buffer();
     99  if (!coreBuffer.IsInSession()) {
    100    return {};
    101  }
    102  return ::mozilla::baseprofiler::AddMarkerToBuffer(
    103      coreBuffer, aName, aCategory, std::move(aOptions), aMarkerType,
    104      aPayloadArguments...);
    105 #endif
    106 }
    107 
    108 // Add a marker (without payload) to the Base Profiler buffer.
    109 inline ProfileBufferBlockIndex AddMarker(const ProfilerString8View& aName,
    110                                         const MarkerCategory& aCategory,
    111                                         MarkerOptions&& aOptions = {}) {
    112  return AddMarker(aName, aCategory, std::move(aOptions), markers::NoPayload{});
    113 }
    114 
    115 }  // namespace mozilla::baseprofiler
    116 
    117 // Same as `AddMarker()` (without payload). This macro is safe to use even if
    118 // MOZ_GECKO_PROFILER is not #defined.
    119 #define BASE_PROFILER_MARKER_UNTYPED(markerName, categoryName, ...)  \
    120  do {                                                               \
    121    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_UNTYPED);               \
    122    ::mozilla::baseprofiler::AddMarker(                              \
    123        markerName, ::mozilla::baseprofiler::category::categoryName, \
    124        ##__VA_ARGS__);                                              \
    125  } while (false)
    126 
    127 // Same as `AddMarker()` (with payload). This macro is safe to use even if
    128 // MOZ_GECKO_PROFILER is not #defined.
    129 #define BASE_PROFILER_MARKER(markerName, categoryName, options, MarkerType,   \
    130                             ...)                                             \
    131  do {                                                                        \
    132    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_with_##MarkerType);              \
    133    ::mozilla::baseprofiler::AddMarker(                                       \
    134        markerName, ::mozilla::baseprofiler::category::categoryName, options, \
    135        ::mozilla::baseprofiler::markers::MarkerType{}, ##__VA_ARGS__);       \
    136  } while (false)
    137 
    138 namespace mozilla::baseprofiler::markers {
    139 // Most common marker type. Others are in BaseProfilerMarkerTypes.h.
    140 struct TextMarker : public BaseMarkerType<TextMarker> {
    141  static constexpr const char* Name = "Text";
    142  // It's not possible to add a single meaningful description to this marker
    143  // type since it can be used by various different markers.
    144  static constexpr const char* Description = nullptr;
    145 
    146  static constexpr bool StoreName = true;
    147 
    148  using MS = MarkerSchema;
    149  static constexpr MS::PayloadField PayloadFields[] =
    150      // XXX - This is confusingly labeled 'name'. We probably want to fix that.
    151      {{"name", MS::InputType::CString, "Details", MS::Format::String,
    152        MS::PayloadFlags::Searchable}};
    153 
    154  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    155                                               MS::Location::MarkerTable};
    156 
    157  static constexpr const char* ChartLabel = "{marker.data.name}";
    158  static constexpr const char* TableLabel =
    159      "{marker.name} - {marker.data.name}";
    160 
    161  static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
    162                                   const ProfilerString8View& aText) {
    163    aWriter.StringProperty("name", aText);
    164  }
    165 };
    166 
    167 struct TextStackMarker : public BaseMarkerType<TextStackMarker> {
    168  static constexpr const char* Name = "TextStack";
    169  // It's not possible to add a single meaningful description to this marker
    170  // type since it can be used by various different markers.
    171  static constexpr const char* Description = nullptr;
    172 
    173  static constexpr bool StoreName = true;
    174 
    175  using MS = MarkerSchema;
    176  static constexpr MS::PayloadField PayloadFields[] =
    177      // XXX - This is confusingly labeled 'name'. We probably want to fix that.
    178      {{"name", MS::InputType::CString, "Details", MS::Format::String,
    179        MS::PayloadFlags::Searchable}};
    180 
    181  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    182                                               MS::Location::MarkerTable};
    183 
    184  static constexpr bool IsStackBased = true;
    185 
    186  static constexpr const char* ChartLabel = "{marker.data.name}";
    187  static constexpr const char* TableLabel =
    188      "{marker.name} - {marker.data.name}";
    189 
    190  static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
    191                                   const ProfilerString8View& aText) {
    192    aWriter.StringProperty("name", aText);
    193  }
    194 };
    195 
    196 // Keep this struct in sync with the `gecko_profiler::marker::Tracing` Rust
    197 // counterpart.
    198 struct Tracing : public BaseMarkerType<Tracing> {
    199  static constexpr const char* Name = "tracing";
    200  // It's not possible to add a single meaningful description to this marker
    201  // type since it can be used by various different markers.
    202  static constexpr const char* Description = nullptr;
    203 
    204  static constexpr bool StoreName = true;
    205 
    206  using MS = MarkerSchema;
    207  static constexpr MS::PayloadField PayloadFields[] = {
    208      {"category", MS::InputType::CString, "Type", MS::Format::String,
    209       MS::PayloadFlags::Searchable}};
    210 
    211  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    212                                               MS::Location::MarkerTable,
    213                                               MS::Location::TimelineOverview};
    214 
    215  static void StreamJSONMarkerData(SpliceableJSONWriter& aWriter,
    216                                   const ProfilerString8View& aCategory) {
    217    if (aCategory.Length() != 0) {
    218      aWriter.StringProperty("category", aCategory);
    219    }
    220  }
    221 };
    222 
    223 // This is the simplest stack based marker
    224 struct StackMarker : public BaseMarkerType<StackMarker> {
    225  static constexpr const char* Name = "StackMarker";
    226  // It's not possible to add a single meaningful description to this marker
    227  // type since it can be used by various different markers.
    228  static constexpr const char* Description = nullptr;
    229 
    230  static constexpr bool StoreName = true;
    231 
    232  using MS = MarkerSchema;
    233  static constexpr MS::PayloadField PayloadFields[0] = {};
    234 
    235  static constexpr MS::Location Locations[] = {MS::Location::MarkerChart,
    236                                               MS::Location::MarkerTable,
    237                                               MS::Location::TimelineOverview};
    238 
    239  static constexpr bool IsStackBased = true;
    240 
    241  static void StreamJSONMarkerData(SpliceableJSONWriter& aWriter) {}
    242 };
    243 
    244 }  // namespace mozilla::baseprofiler::markers
    245 
    246 // Add a text marker. This macro is safe to use even if MOZ_GECKO_PROFILER is
    247 // not #defined.
    248 #define BASE_PROFILER_MARKER_TEXT(markerName, categoryName, options, text)    \
    249  do {                                                                        \
    250    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_TEXT);                           \
    251    ::mozilla::baseprofiler::AddMarker(                                       \
    252        markerName, ::mozilla::baseprofiler::category::categoryName, options, \
    253        ::mozilla::baseprofiler::markers::TextMarker{}, text);                \
    254  } while (false)
    255 
    256 namespace mozilla::baseprofiler {
    257 
    258 // RAII object that adds a BASE_PROFILER_MARKER_TEXT when destroyed; the
    259 // marker's timing will be the interval from construction (unless an instant or
    260 // start time is already specified in the provided options) until destruction.
    261 class MOZ_RAII AutoProfilerTextMarker {
    262 public:
    263  AutoProfilerTextMarker(const char* aMarkerName,
    264                         const MarkerCategory& aCategory,
    265                         MarkerOptions&& aOptions, const std::string& aText)
    266      : mMarkerName(aMarkerName),
    267        mCategory(aCategory),
    268        mOptions(std::move(aOptions)),
    269        mText(aText) {
    270    MOZ_ASSERT(mOptions.Timing().EndTime().IsNull(),
    271               "AutoProfilerTextMarker options shouldn't have an end time");
    272    if (profiler_is_active_and_unpaused() &&
    273        mOptions.Timing().StartTime().IsNull()) {
    274      mOptions.Set(MarkerTiming::InstantNow());
    275    }
    276  }
    277 
    278  ~AutoProfilerTextMarker() {
    279    if (profiler_is_active_and_unpaused()) {
    280      mOptions.TimingRef().SetIntervalEnd();
    281      AUTO_PROFILER_STATS(AUTO_BASE_PROFILER_MARKER_TEXT);
    282      AddMarker(ProfilerString8View::WrapNullTerminatedString(mMarkerName),
    283                mCategory, std::move(mOptions), markers::TextStackMarker{},
    284                mText);
    285    }
    286  }
    287 
    288 protected:
    289  const char* mMarkerName;
    290  MarkerCategory mCategory;
    291  MarkerOptions mOptions;
    292  std::string mText;
    293 };
    294 
    295 #ifdef MOZ_GECKO_PROFILER
    296 extern template MFBT_API ProfileBufferBlockIndex
    297 AddMarker(const ProfilerString8View&, const MarkerCategory&, MarkerOptions&&,
    298          markers::TextMarker, const std::string&);
    299 
    300 extern template MFBT_API ProfileBufferBlockIndex
    301 AddMarkerToBuffer(ProfileChunkedBuffer&, const ProfilerString8View&,
    302                  const MarkerCategory&, MarkerOptions&&, markers::NoPayload);
    303 
    304 extern template MFBT_API ProfileBufferBlockIndex AddMarkerToBuffer(
    305    ProfileChunkedBuffer&, const ProfilerString8View&, const MarkerCategory&,
    306    MarkerOptions&&, markers::TextMarker, const std::string&);
    307 #endif  // MOZ_GECKO_PROFILER
    308 
    309 }  // namespace mozilla::baseprofiler
    310 
    311 // Creates an AutoProfilerTextMarker RAII object.  This macro is safe to use
    312 // even if MOZ_GECKO_PROFILER is not #defined.
    313 #define AUTO_BASE_PROFILER_MARKER_TEXT(markerName, categoryName, options,   \
    314                                       text)                                \
    315  ::mozilla::baseprofiler::AutoProfilerTextMarker PROFILER_RAII(            \
    316      markerName, ::mozilla::baseprofiler::category::categoryName, options, \
    317      text)
    318 
    319 #endif  // BaseProfilerMarkers_h