summaryrefslogtreecommitdiffstats
path: root/mozglue/baseprofiler/public/BaseProfilerMarkers.h
blob: 5821997e7cbb85bf0a911a011f4cd82751774c95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/* -*- 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 basic definitions necessary to create marker types, and
// to add markers to the profiler buffers.
//
// If basic marker types are needed, #include
// "mozilla/BaseProfilerMarkerTypes.h" instead.
//
// But if you want to create your own marker type locally, you can #include this
// header only; look at mozilla/BaseProfilerMarkerTypes.h for examples of how to
// define types, and mozilla/BaseProfilerMarkerPrerequisites.h for some
// supporting 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 BaseProfilerMarkers_h
#define BaseProfilerMarkers_h

#include "mozilla/BaseProfilerMarkersDetail.h"
#include "mozilla/BaseProfilerLabels.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Unused.h"

#include <functional>
#include <string>
#include <utility>

namespace mozilla::baseprofiler {

#ifdef MOZ_GECKO_PROFILER
// Forward-declaration. TODO: Move to more common header, see bug 1681416.
MFBT_API bool profiler_capture_backtrace_into(
    ProfileChunkedBuffer& aChunkedBuffer, 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
// parameters; 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>
ProfileBufferBlockIndex AddMarkerToBuffer(
    ProfileChunkedBuffer& aBuffer, const ProfilerString8View& aName,
    const MarkerCategory& aCategory, MarkerOptions&& aOptions,
    MarkerType aMarkerType, const PayloadArguments&... aPayloadArguments) {
  Unused << aMarkerType;  // Only the empty object type is useful.
  AUTO_BASE_PROFILER_LABEL("baseprofiler::AddMarkerToBuffer", PROFILER);
  return base_profiler_markers_detail::AddMarkerToBuffer<MarkerType>(
      aBuffer, aName, aCategory, std::move(aOptions),
      ::mozilla::baseprofiler::profiler_capture_backtrace_into,
      aPayloadArguments...);
}

// Add a marker (without payload) to a given buffer.
inline ProfileBufferBlockIndex AddMarkerToBuffer(
    ProfileChunkedBuffer& aBuffer, const ProfilerString8View& aName,
    const MarkerCategory& aCategory, MarkerOptions&& aOptions = {}) {
  return AddMarkerToBuffer(aBuffer, aName, aCategory, std::move(aOptions),
                           markers::NoPayload{});
}
#endif  // MOZ_GECKO_PROFILER

// Add a marker to the Base 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>
ProfileBufferBlockIndex AddMarker(
    const ProfilerString8View& aName, const MarkerCategory& aCategory,
    MarkerOptions&& aOptions, MarkerType aMarkerType,
    const PayloadArguments&... aPayloadArguments) {
#ifndef MOZ_GECKO_PROFILER
  return {};
#else
  // Record base markers whenever the core buffer is in session.
  // TODO: When profiler_thread_is_being_profiled becomes available from
  // mozglue, use it instead.
  ProfileChunkedBuffer& coreBuffer =
      ::mozilla::baseprofiler::profiler_get_core_buffer();
  if (!coreBuffer.IsInSession()) {
    return {};
  }
  return ::mozilla::baseprofiler::AddMarkerToBuffer(
      coreBuffer, aName, aCategory, std::move(aOptions), aMarkerType,
      aPayloadArguments...);
#endif
}

// Add a marker (without payload) to the Base Profiler buffer.
inline ProfileBufferBlockIndex AddMarker(const ProfilerString8View& aName,
                                         const MarkerCategory& aCategory,
                                         MarkerOptions&& aOptions = {}) {
  return AddMarker(aName, aCategory, std::move(aOptions), markers::NoPayload{});
}

}  // namespace mozilla::baseprofiler

// Same as `AddMarker()` (without payload). This macro is safe to use even if
// MOZ_GECKO_PROFILER is not #defined.
#define BASE_PROFILER_MARKER_UNTYPED(markerName, categoryName, ...)  \
  do {                                                               \
    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_UNTYPED);               \
    ::mozilla::baseprofiler::AddMarker(                              \
        markerName, ::mozilla::baseprofiler::category::categoryName, \
        ##__VA_ARGS__);                                              \
  } while (false)

// Same as `AddMarker()` (with payload). This macro is safe to use even if
// MOZ_GECKO_PROFILER is not #defined.
#define BASE_PROFILER_MARKER(markerName, categoryName, options, MarkerType,   \
                             ...)                                             \
  do {                                                                        \
    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_with_##MarkerType);              \
    ::mozilla::baseprofiler::AddMarker(                                       \
        markerName, ::mozilla::baseprofiler::category::categoryName, options, \
        ::mozilla::baseprofiler::markers::MarkerType{}, ##__VA_ARGS__);       \
  } while (false)

namespace mozilla::baseprofiler::markers {
// Most common marker type. Others are in BaseProfilerMarkerTypes.h.
struct TextMarker {
  static constexpr Span<const char> MarkerTypeName() {
    return MakeStringSpan("Text");
  }
  static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
                                   const ProfilerString8View& aText) {
    aWriter.StringProperty("name", aText);
  }
  static MarkerSchema MarkerTypeDisplay() {
    using MS = MarkerSchema;
    MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
    schema.SetChartLabel("{marker.data.name}");
    schema.SetTableLabel("{marker.name} - {marker.data.name}");
    schema.AddKeyLabelFormatSearchable("name", "Details", MS::Format::String,
                                       MS::Searchable::Searchable);
    return schema;
  }
};

// Keep this struct in sync with the `gecko_profiler::marker::Tracing` Rust
// counterpart.
struct Tracing {
  static constexpr Span<const char> MarkerTypeName() {
    return MakeStringSpan("tracing");
  }
  static void StreamJSONMarkerData(SpliceableJSONWriter& aWriter,
                                   const ProfilerString8View& aCategory) {
    if (aCategory.Length() != 0) {
      aWriter.StringProperty("category", aCategory);
    }
  }
  static MarkerSchema MarkerTypeDisplay() {
    using MS = MarkerSchema;
    MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable,
              MS::Location::TimelineOverview};
    schema.AddKeyLabelFormatSearchable("category", "Type", MS::Format::String,
                                       MS::Searchable::Searchable);
    return schema;
  }
};
}  // namespace mozilla::baseprofiler::markers

// Add a text marker. This macro is safe to use even if MOZ_GECKO_PROFILER is
// not #defined.
#define BASE_PROFILER_MARKER_TEXT(markerName, categoryName, options, text)    \
  do {                                                                        \
    AUTO_PROFILER_STATS(BASE_PROFILER_MARKER_TEXT);                           \
    ::mozilla::baseprofiler::AddMarker(                                       \
        markerName, ::mozilla::baseprofiler::category::categoryName, options, \
        ::mozilla::baseprofiler::markers::TextMarker{}, text);                \
  } while (false)

namespace mozilla::baseprofiler {

// RAII object that adds a BASE_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 MarkerCategory& aCategory,
                         MarkerOptions&& aOptions, const std::string& 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 (mOptions.Timing().StartTime().IsNull()) {
      mOptions.Set(MarkerTiming::InstantNow());
    }
  }

  ~AutoProfilerTextMarker() {
    mOptions.TimingRef().SetIntervalEnd();
    AUTO_PROFILER_STATS(AUTO_BASE_PROFILER_MARKER_TEXT);
    AddMarker(ProfilerString8View::WrapNullTerminatedString(mMarkerName),
              mCategory, std::move(mOptions), markers::TextMarker{}, mText);
  }

 protected:
  const char* mMarkerName;
  MarkerCategory mCategory;
  MarkerOptions mOptions;
  std::string mText;
};

#ifdef MOZ_GECKO_PROFILER
extern template MFBT_API ProfileBufferBlockIndex
AddMarker(const ProfilerString8View&, const MarkerCategory&, MarkerOptions&&,
          markers::TextMarker, const std::string&);

extern template MFBT_API ProfileBufferBlockIndex
AddMarkerToBuffer(ProfileChunkedBuffer&, const ProfilerString8View&,
                  const MarkerCategory&, MarkerOptions&&, markers::NoPayload);

extern template MFBT_API ProfileBufferBlockIndex AddMarkerToBuffer(
    ProfileChunkedBuffer&, const ProfilerString8View&, const MarkerCategory&,
    MarkerOptions&&, markers::TextMarker, const std::string&);
#endif  // MOZ_GECKO_PROFILER

}  // namespace mozilla::baseprofiler

// Creates an AutoProfilerTextMarker RAII object.  This macro is safe to use
// even if MOZ_GECKO_PROFILER is not #defined.
#define AUTO_BASE_PROFILER_MARKER_TEXT(markerName, categoryName, options,   \
                                       text)                                \
  ::mozilla::baseprofiler::AutoProfilerTextMarker PROFILER_RAII(            \
      markerName, ::mozilla::baseprofiler::category::categoryName, options, \
      text)

#endif  // BaseProfilerMarkers_h