tools/profiler/GeckoProfilerImpl.h

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:fa3ac5c66c3d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // IWYU pragma: private, include "GeckoProfiler.h"
6
7 #ifndef TOOLS_SPS_SAMPLER_H_
8 #define TOOLS_SPS_SAMPLER_H_
9
10 #include <stdlib.h>
11 #include <signal.h>
12 #include <stdarg.h>
13 #include "mozilla/ThreadLocal.h"
14 #include "mozilla/Assertions.h"
15 #include "nscore.h"
16 #include "GeckoProfilerFunc.h"
17 #include "PseudoStack.h"
18 #include "nsISupports.h"
19
20 #ifdef MOZ_TASK_TRACER
21 #include "GeckoTaskTracerImpl.h"
22 #endif
23
24 /* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
25 * this variable name, causing compilation problems. Alleviate this for now by
26 * removing this #define */
27 #ifdef MOZ_WIDGET_QT
28 #undef slots
29 #endif
30
31 // Make sure that we can use std::min here without the Windows headers messing with us.
32 #ifdef min
33 #undef min
34 #endif
35
36 class TableTicker;
37 class JSCustomObject;
38
39 namespace mozilla {
40 class TimeStamp;
41 }
42
43 extern mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
44 extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
45 extern mozilla::ThreadLocal<void *> tlsStackTop;
46 extern bool stack_key_initialized;
47
48 #ifndef SAMPLE_FUNCTION_NAME
49 # ifdef __GNUC__
50 # define SAMPLE_FUNCTION_NAME __FUNCTION__
51 # elif defined(_MSC_VER)
52 # define SAMPLE_FUNCTION_NAME __FUNCTION__
53 # else
54 # define SAMPLE_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name.
55 # endif
56 #endif
57
58 static inline
59 void profiler_init(void* stackTop)
60 {
61 #ifdef MOZ_TASK_TRACER
62 mozilla::tasktracer::InitTaskTracer();
63 #endif
64 mozilla_sampler_init(stackTop);
65 }
66
67 static inline
68 void profiler_shutdown()
69 {
70 #ifdef MOZ_TASK_TRACER
71 mozilla::tasktracer::ShutdownTaskTracer();
72 #endif
73 mozilla_sampler_shutdown();
74 }
75
76 static inline
77 void profiler_start(int aProfileEntries, int aInterval,
78 const char** aFeatures, uint32_t aFeatureCount,
79 const char** aThreadNameFilters, uint32_t aFilterCount)
80 {
81 mozilla_sampler_start(aProfileEntries, aInterval, aFeatures, aFeatureCount, aThreadNameFilters, aFilterCount);
82 }
83
84 static inline
85 void profiler_stop()
86 {
87 mozilla_sampler_stop();
88 }
89
90 static inline
91 bool profiler_is_paused()
92 {
93 return mozilla_sampler_is_paused();
94 }
95
96 static inline
97 void profiler_pause()
98 {
99 mozilla_sampler_pause();
100 }
101
102 static inline
103 void profiler_resume()
104 {
105 mozilla_sampler_resume();
106 }
107
108 static inline
109 ProfilerBacktrace* profiler_get_backtrace()
110 {
111 return mozilla_sampler_get_backtrace();
112 }
113
114 static inline
115 void profiler_free_backtrace(ProfilerBacktrace* aBacktrace)
116 {
117 mozilla_sampler_free_backtrace(aBacktrace);
118 }
119
120 static inline
121 bool profiler_is_active()
122 {
123 return mozilla_sampler_is_active();
124 }
125
126 static inline
127 void profiler_responsiveness(const mozilla::TimeStamp& aTime)
128 {
129 mozilla_sampler_responsiveness(aTime);
130 }
131
132 static inline
133 const double* profiler_get_responsiveness()
134 {
135 return mozilla_sampler_get_responsiveness();
136 }
137
138 static inline
139 void profiler_set_frame_number(int frameNumber)
140 {
141 return mozilla_sampler_frame_number(frameNumber);
142 }
143
144 static inline
145 char* profiler_get_profile()
146 {
147 return mozilla_sampler_get_profile();
148 }
149
150 static inline
151 JSObject* profiler_get_profile_jsobject(JSContext* aCx)
152 {
153 return mozilla_sampler_get_profile_data(aCx);
154 }
155
156 static inline
157 void profiler_save_profile_to_file(const char* aFilename)
158 {
159 return mozilla_sampler_save_profile_to_file(aFilename);
160 }
161
162 static inline
163 const char** profiler_get_features()
164 {
165 return mozilla_sampler_get_features();
166 }
167
168 static inline
169 void profiler_print_location()
170 {
171 if (!sps_version2()) {
172 return mozilla_sampler_print_location1();
173 } else {
174 return mozilla_sampler_print_location2();
175 }
176 }
177
178 static inline
179 void profiler_lock()
180 {
181 return mozilla_sampler_lock();
182 }
183
184 static inline
185 void profiler_unlock()
186 {
187 return mozilla_sampler_unlock();
188 }
189
190 static inline
191 void profiler_register_thread(const char* name, void* stackTop)
192 {
193 mozilla_sampler_register_thread(name, stackTop);
194 }
195
196 static inline
197 void profiler_unregister_thread()
198 {
199 mozilla_sampler_unregister_thread();
200 }
201
202 static inline
203 void profiler_sleep_start()
204 {
205 mozilla_sampler_sleep_start();
206 }
207
208 static inline
209 void profiler_sleep_end()
210 {
211 mozilla_sampler_sleep_end();
212 }
213
214 static inline
215 void profiler_js_operation_callback()
216 {
217 PseudoStack *stack = tlsPseudoStack.get();
218 if (!stack) {
219 return;
220 }
221
222 stack->jsOperationCallback();
223 }
224
225 static inline
226 double profiler_time()
227 {
228 return mozilla_sampler_time();
229 }
230
231 static inline
232 double profiler_time(const mozilla::TimeStamp& aTime)
233 {
234 return mozilla_sampler_time(aTime);
235 }
236
237 static inline
238 bool profiler_in_privacy_mode()
239 {
240 PseudoStack *stack = tlsPseudoStack.get();
241 if (!stack) {
242 return false;
243 }
244 return stack->mPrivacyMode;
245 }
246
247 static inline void profiler_tracing(const char* aCategory, const char* aInfo,
248 TracingMetadata aMetaData = TRACING_DEFAULT)
249 {
250 if (!stack_key_initialized)
251 return;
252
253 // Don't insert a marker if we're not profiling to avoid
254 // the heap copy (malloc).
255 if (!profiler_is_active()) {
256 return;
257 }
258
259 mozilla_sampler_tracing(aCategory, aInfo, aMetaData);
260 }
261
262 // Uncomment this to turn on systrace or build with
263 // ac_add_options --enable-systace
264 //#define MOZ_USE_SYSTRACE
265 #ifdef MOZ_USE_SYSTRACE
266 # define ATRACE_TAG ATRACE_TAG_GRAPHICS
267 // We need HAVE_ANDROID_OS to be defined for Trace.h.
268 // If its not set we will set it temporary and remove it.
269 # ifndef HAVE_ANDROID_OS
270 # define HAVE_ANDROID_OS
271 # define REMOVE_HAVE_ANDROID_OS
272 # endif
273 # include <utils/Trace.h>
274 # define MOZ_PLATFORM_TRACING ATRACE_CALL();
275 # ifdef REMOVE_HAVE_ANDROID_OS
276 # undef HAVE_ANDROID_OS
277 # undef REMOVE_HAVE_ANDROID_OS
278 # endif
279 #else
280 # define MOZ_PLATFORM_TRACING
281 #endif
282
283 // we want the class and function name but can't easily get that using preprocessor macros
284 // __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
285
286 #define SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line
287 #define SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, line) SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line)
288 #define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
289
290 #define PROFILER_LABEL(name_space, info) MOZ_PLATFORM_TRACING mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
291 #define PROFILER_LABEL_PRINTF(name_space, info, ...) MOZ_PLATFORM_TRACING mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
292
293 #define PROFILER_MARKER(info) mozilla_sampler_add_marker(info)
294 #define PROFILER_MARKER_PAYLOAD(info, payload) mozilla_sampler_add_marker(info, payload)
295 #define PROFILER_MAIN_THREAD_MARKER(info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info)
296
297 #define PROFILER_MAIN_THREAD_LABEL(name_space, info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__)
298 #define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, ...) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
299
300
301 /* FIXME/bug 789667: memory constraints wouldn't much of a problem for
302 * this small a sample buffer size, except that serializing the
303 * profile data is extremely, unnecessarily memory intensive. */
304 #ifdef MOZ_WIDGET_GONK
305 # define PLATFORM_LIKELY_MEMORY_CONSTRAINED
306 #endif
307
308 #if !defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) && !defined(ARCH_ARMV6)
309 # define PROFILE_DEFAULT_ENTRY 1000000
310 #else
311 # define PROFILE_DEFAULT_ENTRY 100000
312 #endif
313
314 // In the case of profiler_get_backtrace we know that we only need enough space
315 // for a single backtrace.
316 #define GET_BACKTRACE_DEFAULT_ENTRY 1000
317
318 #if defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED)
319 /* A 1ms sampling interval has been shown to be a large perf hit
320 * (10fps) on memory-contrained (low-end) platforms, and additionally
321 * to yield different results from the profiler. Where this is the
322 * important case, b2g, there are also many gecko processes which
323 * magnify these effects. */
324 # define PROFILE_DEFAULT_INTERVAL 10
325 #elif defined(ANDROID)
326 // We use a lower frequency on Android, in order to make things work
327 // more smoothly on phones. This value can be adjusted later with
328 // some libunwind optimizations.
329 // In one sample measurement on Galaxy Nexus, out of about 700 backtraces,
330 // 60 of them took more than 25ms, and the average and standard deviation
331 // were 6.17ms and 9.71ms respectively.
332
333 // For now since we don't support stackwalking let's use 1ms since it's fast
334 // enough.
335 #define PROFILE_DEFAULT_INTERVAL 1
336 #else
337 #define PROFILE_DEFAULT_INTERVAL 1
338 #endif
339 #define PROFILE_DEFAULT_FEATURES NULL
340 #define PROFILE_DEFAULT_FEATURE_COUNT 0
341
342 namespace mozilla {
343
344 class MOZ_STACK_CLASS SamplerStackFrameRAII {
345 public:
346 // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
347 SamplerStackFrameRAII(const char *aInfo, uint32_t line) {
348 mHandle = mozilla_sampler_call_enter(aInfo, this, false, line);
349 }
350 ~SamplerStackFrameRAII() {
351 mozilla_sampler_call_exit(mHandle);
352 }
353 private:
354 void* mHandle;
355 };
356
357 static const int SAMPLER_MAX_STRING = 128;
358 class MOZ_STACK_CLASS SamplerStackFramePrintfRAII {
359 public:
360 // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
361 SamplerStackFramePrintfRAII(const char *aDefault, uint32_t line, const char *aFormat, ...) {
362 if (profiler_is_active() && !profiler_in_privacy_mode()) {
363 va_list args;
364 va_start(args, aFormat);
365 char buff[SAMPLER_MAX_STRING];
366
367 // We have to use seperate printf's because we're using
368 // the vargs.
369 #if _MSC_VER
370 _vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
371 _snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
372 #else
373 ::vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
374 ::snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
375 #endif
376 mHandle = mozilla_sampler_call_enter(mDest, this, true, line);
377 va_end(args);
378 } else {
379 mHandle = mozilla_sampler_call_enter(aDefault, this, false, line);
380 }
381 }
382 ~SamplerStackFramePrintfRAII() {
383 mozilla_sampler_call_exit(mHandle);
384 }
385 private:
386 char mDest[SAMPLER_MAX_STRING];
387 void* mHandle;
388 };
389
390 } //mozilla
391
392 inline PseudoStack* mozilla_get_pseudo_stack(void)
393 {
394 if (!stack_key_initialized)
395 return nullptr;
396 return tlsPseudoStack.get();
397 }
398
399 inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress,
400 bool aCopy, uint32_t line)
401 {
402 // check if we've been initialized to avoid calling pthread_getspecific
403 // with a null tlsStack which will return undefined results.
404 if (!stack_key_initialized)
405 return nullptr;
406
407 PseudoStack *stack = tlsPseudoStack.get();
408 // we can't infer whether 'stack' has been initialized
409 // based on the value of stack_key_intiailized because
410 // 'stack' is only intialized when a thread is being
411 // profiled.
412 if (!stack) {
413 return stack;
414 }
415 stack->push(aInfo, aFrameAddress, aCopy, line);
416
417 // The handle is meant to support future changes
418 // but for now it is simply use to save a call to
419 // pthread_getspecific on exit. It also supports the
420 // case where the sampler is initialized between
421 // enter and exit.
422 return stack;
423 }
424
425 inline void mozilla_sampler_call_exit(void *aHandle)
426 {
427 if (!aHandle)
428 return;
429
430 PseudoStack *stack = (PseudoStack*)aHandle;
431 stack->pop();
432 }
433
434 void mozilla_sampler_add_marker(const char *aMarker, ProfilerMarkerPayload *aPayload);
435
436 #endif /* ndef TOOLS_SPS_SAMPLER_H_ */

mercurial