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.

     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"
     7 #ifndef TOOLS_SPS_SAMPLER_H_
     8 #define TOOLS_SPS_SAMPLER_H_
    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"
    20 #ifdef MOZ_TASK_TRACER
    21 #include "GeckoTaskTracerImpl.h"
    22 #endif
    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
    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
    36 class TableTicker;
    37 class JSCustomObject;
    39 namespace mozilla {
    40 class TimeStamp;
    41 }
    43 extern mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
    44 extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
    45 extern mozilla::ThreadLocal<void *> tlsStackTop;
    46 extern bool stack_key_initialized;
    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
    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 }
    67 static inline
    68 void profiler_shutdown()
    69 {
    70 #ifdef MOZ_TASK_TRACER
    71   mozilla::tasktracer::ShutdownTaskTracer();
    72 #endif
    73   mozilla_sampler_shutdown();
    74 }
    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 }
    84 static inline
    85 void profiler_stop()
    86 {
    87   mozilla_sampler_stop();
    88 }
    90 static inline
    91 bool profiler_is_paused()
    92 {
    93   return mozilla_sampler_is_paused();
    94 }
    96 static inline
    97 void profiler_pause()
    98 {
    99   mozilla_sampler_pause();
   100 }
   102 static inline
   103 void profiler_resume()
   104 {
   105   mozilla_sampler_resume();
   106 }
   108 static inline
   109 ProfilerBacktrace* profiler_get_backtrace()
   110 {
   111   return mozilla_sampler_get_backtrace();
   112 }
   114 static inline
   115 void profiler_free_backtrace(ProfilerBacktrace* aBacktrace)
   116 {
   117   mozilla_sampler_free_backtrace(aBacktrace);
   118 }
   120 static inline
   121 bool profiler_is_active()
   122 {
   123   return mozilla_sampler_is_active();
   124 }
   126 static inline
   127 void profiler_responsiveness(const mozilla::TimeStamp& aTime)
   128 {
   129   mozilla_sampler_responsiveness(aTime);
   130 }
   132 static inline
   133 const double* profiler_get_responsiveness()
   134 {
   135   return mozilla_sampler_get_responsiveness();
   136 }
   138 static inline
   139 void profiler_set_frame_number(int frameNumber)
   140 {
   141   return mozilla_sampler_frame_number(frameNumber);
   142 }
   144 static inline
   145 char* profiler_get_profile()
   146 {
   147   return mozilla_sampler_get_profile();
   148 }
   150 static inline
   151 JSObject* profiler_get_profile_jsobject(JSContext* aCx)
   152 {
   153   return mozilla_sampler_get_profile_data(aCx);
   154 }
   156 static inline
   157 void profiler_save_profile_to_file(const char* aFilename)
   158 {
   159   return mozilla_sampler_save_profile_to_file(aFilename);
   160 }
   162 static inline
   163 const char** profiler_get_features()
   164 {
   165   return mozilla_sampler_get_features();
   166 }
   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 }
   178 static inline
   179 void profiler_lock()
   180 {
   181   return mozilla_sampler_lock();
   182 }
   184 static inline
   185 void profiler_unlock()
   186 {
   187   return mozilla_sampler_unlock();
   188 }
   190 static inline
   191 void profiler_register_thread(const char* name, void* stackTop)
   192 {
   193   mozilla_sampler_register_thread(name, stackTop);
   194 }
   196 static inline
   197 void profiler_unregister_thread()
   198 {
   199   mozilla_sampler_unregister_thread();
   200 }
   202 static inline
   203 void profiler_sleep_start()
   204 {
   205   mozilla_sampler_sleep_start();
   206 }
   208 static inline
   209 void profiler_sleep_end()
   210 {
   211   mozilla_sampler_sleep_end();
   212 }
   214 static inline
   215 void profiler_js_operation_callback()
   216 {
   217   PseudoStack *stack = tlsPseudoStack.get();
   218   if (!stack) {
   219     return;
   220   }
   222   stack->jsOperationCallback();
   223 }
   225 static inline
   226 double profiler_time()
   227 {
   228   return mozilla_sampler_time();
   229 }
   231 static inline
   232 double profiler_time(const mozilla::TimeStamp& aTime)
   233 {
   234   return mozilla_sampler_time(aTime);
   235 }
   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 }
   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;
   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   }
   259   mozilla_sampler_tracing(aCategory, aInfo, aMetaData);
   260 }
   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
   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
   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__)
   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__)
   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)
   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__)
   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
   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
   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
   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.
   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
   342 namespace mozilla {
   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 };
   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];
   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 };
   390 } //mozilla
   392 inline PseudoStack* mozilla_get_pseudo_stack(void)
   393 {
   394   if (!stack_key_initialized)
   395     return nullptr;
   396   return tlsPseudoStack.get();
   397 }
   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;
   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);
   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 }
   425 inline void mozilla_sampler_call_exit(void *aHandle)
   426 {
   427   if (!aHandle)
   428     return;
   430   PseudoStack *stack = (PseudoStack*)aHandle;
   431   stack->pop();
   432 }
   434 void mozilla_sampler_add_marker(const char *aMarker, ProfilerMarkerPayload *aPayload);
   436 #endif /* ndef TOOLS_SPS_SAMPLER_H_ */

mercurial