summaryrefslogtreecommitdiffstats
path: root/tools/profiler/public/ProfilerMarkers.h
blob: de2e6f881d704d85a952b220a7fd97737308f4b8 (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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/* -*- 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"

#ifndef MOZ_GECKO_PROFILER

#  define PROFILER_MARKER_UNTYPED(markerName, categoryName, ...)
#  define PROFILER_MARKER(markerName, categoryName, options, MarkerType, ...)
#  define PROFILER_MARKER_TEXT(markerName, categoryName, options, text)
#  define AUTO_PROFILER_MARKER_TEXT(markerName, categoryName, options, text)
#  define AUTO_PROFILER_TRACING_MARKER(categoryString, markerName, categoryPair)
#  define AUTO_PROFILER_TRACING_MARKER_DOCSHELL(categoryString, markerName, \
                                                categoryPair, docShell)

#else  // ndef MOZ_GECKO_PROFILER

namespace mozilla {
class ProfileChunkedBuffer;
}

bool profiler_can_accept_markers();
bool profiler_capture_backtrace_into(
    mozilla::ProfileChunkedBuffer& aChunkedBuffer);

// 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;
}

// 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) {
  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_capture_backtrace_into, 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{});
}

// 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) {
  if (!profiler_can_accept_markers()) {
    return {};
  }
  return ::AddMarkerToBuffer(profiler_markers_detail::CachedCoreBuffer(), aName,
                             aCategory, std::move(aOptions), aMarkerType,
                             aPayloadArguments...);
}

// 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 (mOptions.Timing().StartTime().IsNull()) {
      mOptions.Set(mozilla::MarkerTiming::InstantNow());
    }
  }

  ~AutoProfilerTextMarker() {
    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_DOCSHELL(categoryString, markerName, \
                                                categoryPair, docShell)     \
    AutoProfilerTracing PROFILER_RAII(                                      \
        categoryString, markerName, geckoprofiler::category::categoryPair,  \
        profiler_get_inner_window_id_from_docshell(docShell))

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  // nfed MOZ_GECKO_PROFILER else

#endif  // ProfilerMarkers_h