Backed out 3 changesets (bug 1901078, bug 1749048) for causing interface related...
[gecko.git] / tools / profiler / public / ProfilerLabels.h
bloba1585d8dd824c1ea1b53afbc9d3cb6fb8173923a
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/. */
7 // This header contains all definitions related to profiler labels.
8 // It is safe to include unconditionally, and only defines empty macros if
9 // MOZ_GECKO_PROFILER is not set.
11 #ifndef ProfilerLabels_h
12 #define ProfilerLabels_h
14 #include "mozilla/ProfilerState.h"
15 #include "mozilla/ProfilerThreadState.h"
17 #include "js/ProfilingCategory.h"
18 #include "js/ProfilingStack.h"
19 #include "js/RootingAPI.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/BaseProfilerRAIIMacro.h"
24 #include "mozilla/Maybe.h"
25 #include "mozilla/ProfilerThreadRegistration.h"
26 #include "mozilla/ThreadLocal.h"
27 #include "nsString.h"
29 #include <stdint.h>
31 struct JSContext;
33 // Insert an RAII object in this scope to enter a label stack frame. Any
34 // samples collected in this scope will contain this label in their stack.
35 // The label argument must be a static C string. It is usually of the
36 // form "ClassName::FunctionName". (Ideally we'd use the compiler to provide
37 // that for us, but __func__ gives us the function name without the class
38 // name.) If the label applies to only part of a function, you can qualify it
39 // like this: "ClassName::FunctionName:PartName".
41 // Use AUTO_PROFILER_LABEL_DYNAMIC_* if you want to add additional / dynamic
42 // information to the label stack frame, and AUTO_PROFILER_LABEL_HOT if you're
43 // instrumenting functions for which overhead on the order of nanoseconds is
44 // noticeable.
45 #define AUTO_PROFILER_LABEL(label, categoryPair) \
46 mozilla::AutoProfilerLabel PROFILER_RAII( \
47 label, nullptr, JS::ProfilingCategoryPair::categoryPair)
49 // Like AUTO_PROFILER_LABEL, but for super-hot code where overhead must be
50 // kept to the absolute minimum. This variant doesn't push the label if the
51 // profiler isn't running.
52 // Don't use this for long-running functions: If the profiler is started in
53 // the middle of the function, this label won't be on the stack until the
54 // function is entered the next time. As a result, category information for
55 // samples at the start of the profile can be misleading.
56 // For short-running functions, that's often an acceptable trade-off.
57 #define AUTO_PROFILER_LABEL_HOT(label, categoryPair) \
58 mozilla::AutoProfilerLabelHot PROFILER_RAII( \
59 label, nullptr, JS::ProfilingCategoryPair::categoryPair)
61 // Similar to AUTO_PROFILER_LABEL, but that adds the RELEVANT_FOR_JS flag.
62 #define AUTO_PROFILER_LABEL_RELEVANT_FOR_JS(label, categoryPair) \
63 mozilla::AutoProfilerLabel PROFILER_RAII( \
64 label, nullptr, JS::ProfilingCategoryPair::categoryPair, \
65 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS))
67 // Similar to AUTO_PROFILER_LABEL, but with only one argument: the category
68 // pair. The label string is taken from the category pair. This is convenient
69 // for labels like AUTO_PROFILER_LABEL_CATEGORY_PAIR(GRAPHICS_LayerBuilding)
70 // which would otherwise just repeat the string.
71 #define AUTO_PROFILER_LABEL_CATEGORY_PAIR(categoryPair) \
72 mozilla::AutoProfilerLabel PROFILER_RAII( \
73 "", nullptr, JS::ProfilingCategoryPair::categoryPair, \
74 uint32_t( \
75 js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR))
77 // Similar to AUTO_PROFILER_LABEL_CATEGORY_PAIR but adding the RELEVANT_FOR_JS
78 // flag.
79 #define AUTO_PROFILER_LABEL_CATEGORY_PAIR_RELEVANT_FOR_JS(categoryPair) \
80 mozilla::AutoProfilerLabel PROFILER_RAII( \
81 "", nullptr, JS::ProfilingCategoryPair::categoryPair, \
82 uint32_t( \
83 js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR) | \
84 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS))
86 // Similar to AUTO_PROFILER_LABEL, but with an additional string. The inserted
87 // RAII object stores the cStr pointer in a field; it does not copy the string.
89 // WARNING: This means that the string you pass to this macro needs to live at
90 // least until the end of the current scope. Be careful using this macro with
91 // ns[C]String; the other AUTO_PROFILER_LABEL_DYNAMIC_* macros below are
92 // preferred because they avoid this problem.
94 // If the profiler samples the current thread and walks the label stack while
95 // this RAII object is on the stack, it will copy the supplied string into the
96 // profile buffer. So there's one string copy operation, and it happens at
97 // sample time.
99 // Compare this to the plain AUTO_PROFILER_LABEL macro, which only accepts
100 // literal strings: When the label stack frames generated by
101 // AUTO_PROFILER_LABEL are sampled, no string copy needs to be made because the
102 // profile buffer can just store the raw pointers to the literal strings.
103 // Consequently, AUTO_PROFILER_LABEL frames take up considerably less space in
104 // the profile buffer than AUTO_PROFILER_LABEL_DYNAMIC_* frames.
105 #define AUTO_PROFILER_LABEL_DYNAMIC_CSTR(label, categoryPair, cStr) \
106 mozilla::AutoProfilerLabel PROFILER_RAII( \
107 label, cStr, JS::ProfilingCategoryPair::categoryPair)
109 // Like AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but with the NONSENSITIVE flag to
110 // note that it does not contain sensitive information (so we can include it
111 // in, for example, the BackgroundHangMonitor)
112 #define AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE(label, categoryPair, \
113 cStr) \
114 mozilla::AutoProfilerLabel PROFILER_RAII( \
115 label, cStr, JS::ProfilingCategoryPair::categoryPair, \
116 uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE))
118 // Similar to AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but takes an nsACString.
120 // Note: The use of the Maybe<>s ensures the scopes for the dynamic string and
121 // the AutoProfilerLabel are appropriate, while also not incurring the runtime
122 // cost of the string assignment unless the profiler is active. Therefore,
123 // unlike AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC_CSTR, this macro
124 // doesn't push/pop a label when the profiler is inactive.
125 #define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(label, categoryPair, nsCStr) \
126 mozilla::Maybe<nsAutoCString> autoCStr; \
127 mozilla::Maybe<mozilla::AutoProfilerLabel> raiiObjectNsCString; \
128 if (profiler_is_active()) { \
129 autoCStr.emplace(nsCStr); \
130 raiiObjectNsCString.emplace(label, autoCStr->get(), \
131 JS::ProfilingCategoryPair::categoryPair); \
134 #define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_RELEVANT_FOR_JS( \
135 label, categoryPair, nsCStr) \
136 mozilla::Maybe<nsAutoCString> autoCStr; \
137 mozilla::Maybe<mozilla::AutoProfilerLabel> raiiObjectNsCString; \
138 if (profiler_is_active()) { \
139 autoCStr.emplace(nsCStr); \
140 raiiObjectNsCString.emplace( \
141 label, autoCStr->get(), JS::ProfilingCategoryPair::categoryPair, \
142 uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); \
145 // Match the conditions for MOZ_ENABLE_BACKGROUND_HANG_MONITOR
146 #if defined(NIGHTLY_BUILD) && !defined(MOZ_DEBUG) && !defined(MOZ_TSAN) && \
147 !defined(MOZ_ASAN)
148 # define SHOULD_CREATE_ALL_NONSENSITIVE_LABEL_FRAMES true
149 #else
150 # define SHOULD_CREATE_ALL_NONSENSITIVE_LABEL_FRAMES profiler_is_active()
151 #endif
153 // See note above AUTO_PROFILER_LABEL_DYNAMIC_CSTR_NONSENSITIVE
154 #define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_NONSENSITIVE( \
155 label, categoryPair, nsCStr) \
156 mozilla::Maybe<nsAutoCString> autoCStr; \
157 mozilla::Maybe<mozilla::AutoProfilerLabel> raiiObjectNsCString; \
158 if (SHOULD_CREATE_ALL_NONSENSITIVE_LABEL_FRAMES) { \
159 autoCStr.emplace(nsCStr); \
160 raiiObjectNsCString.emplace( \
161 label, autoCStr->get(), JS::ProfilingCategoryPair::categoryPair, \
162 uint32_t(js::ProfilingStackFrame::Flags::NONSENSITIVE)); \
165 // Similar to AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but takes an nsString that is
166 // is lossily converted to an ASCII string.
168 // Note: The use of the Maybe<>s ensures the scopes for the converted dynamic
169 // string and the AutoProfilerLabel are appropriate, while also not incurring
170 // the runtime cost of the string conversion unless the profiler is active.
171 // Therefore, unlike AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC_CSTR,
172 // this macro doesn't push/pop a label when the profiler is inactive.
173 #define AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(label, categoryPair, nsStr) \
174 mozilla::Maybe<NS_LossyConvertUTF16toASCII> asciiStr; \
175 mozilla::Maybe<mozilla::AutoProfilerLabel> raiiObjectLossyNsString; \
176 if (profiler_is_active()) { \
177 asciiStr.emplace(nsStr); \
178 raiiObjectLossyNsString.emplace(label, asciiStr->get(), \
179 JS::ProfilingCategoryPair::categoryPair); \
182 // Similar to AUTO_PROFILER_LABEL, but accepting a JSContext* parameter, and a
183 // no-op if the profiler is disabled.
184 // Used to annotate functions for which overhead in the range of nanoseconds is
185 // noticeable. It avoids overhead from the TLS lookup because it can get the
186 // ProfilingStack from the JS context, and avoids almost all overhead in the
187 // case where the profiler is disabled.
188 #define AUTO_PROFILER_LABEL_FAST(label, categoryPair, ctx) \
189 mozilla::AutoProfilerLabelHot PROFILER_RAII( \
190 ctx, label, nullptr, JS::ProfilingCategoryPair::categoryPair)
192 // Similar to AUTO_PROFILER_LABEL_FAST, but also takes an extra string and an
193 // additional set of flags. The flags parameter should carry values from the
194 // js::ProfilingStackFrame::Flags enum.
195 #define AUTO_PROFILER_LABEL_DYNAMIC_FAST(label, dynamicString, categoryPair, \
196 ctx, flags) \
197 mozilla::AutoProfilerLabelHot PROFILER_RAII( \
198 ctx, label, dynamicString, JS::ProfilingCategoryPair::categoryPair, \
199 flags)
201 namespace mozilla {
203 #ifndef MOZ_GECKO_PROFILER
205 class MOZ_RAII AutoProfilerLabel {
206 public:
207 // This is the AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC variant.
208 AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
209 JS::ProfilingCategoryPair aCategoryPair,
210 uint32_t aFlags = 0) {}
212 ~AutoProfilerLabel() {}
215 class MOZ_RAII AutoProfilerLabelHot {
216 public:
217 // This is the AUTO_PROFILER_LABEL_HOT variant.
218 AutoProfilerLabelHot(const char* aLabel, const char* aDynamicString,
219 JS::ProfilingCategoryPair aCategoryPair,
220 uint32_t aFlags = 0) {}
222 // This is the AUTO_PROFILER_LABEL_FAST variant.
223 AutoProfilerLabelHot(JSContext* aJSContext, const char* aLabel,
224 const char* aDynamicString,
225 JS::ProfilingCategoryPair aCategoryPair,
226 uint32_t aFlags) {}
228 ~AutoProfilerLabelHot() {}
231 #else // !MOZ_GECKO_PROFILER
233 // This class creates a non-owning ProfilingStack reference. Objects of this
234 // class are stack-allocated, and so exist within a thread, and are thus bounded
235 // by the lifetime of the thread, which ensures that the references held can't
236 // be used after the ProfilingStack is destroyed.
237 class MOZ_RAII AutoProfilerLabel {
238 public:
239 // This is the AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC variant.
240 AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
241 JS::ProfilingCategoryPair aCategoryPair,
242 uint32_t aFlags = 0) {
243 // Get the ProfilingStack from TLS.
244 mProfilingStack = profiler::ThreadRegistration::WithOnThreadRefOr(
245 [](profiler::ThreadRegistration::OnThreadRef aThread) {
246 return &aThread.UnlockedConstReaderAndAtomicRWRef()
247 .ProfilingStackRef();
249 nullptr);
250 if (mProfilingStack) {
251 mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this,
252 aCategoryPair, aFlags);
256 ~AutoProfilerLabel() {
257 // This function runs both on and off the main thread.
259 if (mProfilingStack) {
260 mProfilingStack->pop();
264 private:
265 // We save a ProfilingStack pointer in the ctor so we don't have to redo the
266 // TLS lookup in the dtor.
267 ProfilingStack* mProfilingStack;
270 class MOZ_RAII AutoProfilerLabelHot {
271 public:
272 // This is the AUTO_PROFILER_LABEL_HOT variant. It does nothing if
273 // the profiler is inactive.
274 AutoProfilerLabelHot(const char* aLabel, const char* aDynamicString,
275 JS::ProfilingCategoryPair aCategoryPair,
276 uint32_t aFlags = 0) {
277 if (MOZ_LIKELY(!profiler_is_active())) {
278 mProfilingStack = nullptr;
279 return;
282 // Get the ProfilingStack from TLS.
283 mProfilingStack = profiler::ThreadRegistration::WithOnThreadRefOr(
284 [](profiler::ThreadRegistration::OnThreadRef aThread) {
285 return &aThread.UnlockedConstReaderAndAtomicRWRef()
286 .ProfilingStackRef();
288 nullptr);
289 if (mProfilingStack) {
290 mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this,
291 aCategoryPair, aFlags);
295 // This is the AUTO_PROFILER_LABEL_FAST variant. It retrieves the
296 // ProfilingStack from the JSContext and does nothing if the profiler is
297 // inactive.
298 AutoProfilerLabelHot(JSContext* aJSContext, const char* aLabel,
299 const char* aDynamicString,
300 JS::ProfilingCategoryPair aCategoryPair,
301 uint32_t aFlags) {
302 mProfilingStack = js::GetContextProfilingStackIfEnabled(aJSContext);
303 if (MOZ_UNLIKELY(mProfilingStack)) {
304 mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this,
305 aCategoryPair, aFlags);
309 ~AutoProfilerLabelHot() {
310 // This function runs both on and off the main thread.
311 if (MOZ_UNLIKELY(mProfilingStack)) {
312 mProfilingStack->pop();
316 private:
317 // We save a ProfilingStack pointer in the ctor so we don't have to redo the
318 // TLS lookup in the dtor.
319 ProfilingStack* mProfilingStack;
322 #endif // !MOZ_GECKO_PROFILER
324 } // namespace mozilla
326 #endif // ProfilerLabels_h