tools/profiler/GeckoProfilerImpl.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial