1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/GeckoProfilerImpl.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,436 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +// IWYU pragma: private, include "GeckoProfiler.h" 1.9 + 1.10 +#ifndef TOOLS_SPS_SAMPLER_H_ 1.11 +#define TOOLS_SPS_SAMPLER_H_ 1.12 + 1.13 +#include <stdlib.h> 1.14 +#include <signal.h> 1.15 +#include <stdarg.h> 1.16 +#include "mozilla/ThreadLocal.h" 1.17 +#include "mozilla/Assertions.h" 1.18 +#include "nscore.h" 1.19 +#include "GeckoProfilerFunc.h" 1.20 +#include "PseudoStack.h" 1.21 +#include "nsISupports.h" 1.22 + 1.23 +#ifdef MOZ_TASK_TRACER 1.24 +#include "GeckoTaskTracerImpl.h" 1.25 +#endif 1.26 + 1.27 +/* QT has a #define for the word "slots" and jsfriendapi.h has a struct with 1.28 + * this variable name, causing compilation problems. Alleviate this for now by 1.29 + * removing this #define */ 1.30 +#ifdef MOZ_WIDGET_QT 1.31 +#undef slots 1.32 +#endif 1.33 + 1.34 +// Make sure that we can use std::min here without the Windows headers messing with us. 1.35 +#ifdef min 1.36 +#undef min 1.37 +#endif 1.38 + 1.39 +class TableTicker; 1.40 +class JSCustomObject; 1.41 + 1.42 +namespace mozilla { 1.43 +class TimeStamp; 1.44 +} 1.45 + 1.46 +extern mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack; 1.47 +extern mozilla::ThreadLocal<TableTicker *> tlsTicker; 1.48 +extern mozilla::ThreadLocal<void *> tlsStackTop; 1.49 +extern bool stack_key_initialized; 1.50 + 1.51 +#ifndef SAMPLE_FUNCTION_NAME 1.52 +# ifdef __GNUC__ 1.53 +# define SAMPLE_FUNCTION_NAME __FUNCTION__ 1.54 +# elif defined(_MSC_VER) 1.55 +# define SAMPLE_FUNCTION_NAME __FUNCTION__ 1.56 +# else 1.57 +# define SAMPLE_FUNCTION_NAME __func__ // defined in C99, supported in various C++ compilers. Just raw function name. 1.58 +# endif 1.59 +#endif 1.60 + 1.61 +static inline 1.62 +void profiler_init(void* stackTop) 1.63 +{ 1.64 +#ifdef MOZ_TASK_TRACER 1.65 + mozilla::tasktracer::InitTaskTracer(); 1.66 +#endif 1.67 + mozilla_sampler_init(stackTop); 1.68 +} 1.69 + 1.70 +static inline 1.71 +void profiler_shutdown() 1.72 +{ 1.73 +#ifdef MOZ_TASK_TRACER 1.74 + mozilla::tasktracer::ShutdownTaskTracer(); 1.75 +#endif 1.76 + mozilla_sampler_shutdown(); 1.77 +} 1.78 + 1.79 +static inline 1.80 +void profiler_start(int aProfileEntries, int aInterval, 1.81 + const char** aFeatures, uint32_t aFeatureCount, 1.82 + const char** aThreadNameFilters, uint32_t aFilterCount) 1.83 +{ 1.84 + mozilla_sampler_start(aProfileEntries, aInterval, aFeatures, aFeatureCount, aThreadNameFilters, aFilterCount); 1.85 +} 1.86 + 1.87 +static inline 1.88 +void profiler_stop() 1.89 +{ 1.90 + mozilla_sampler_stop(); 1.91 +} 1.92 + 1.93 +static inline 1.94 +bool profiler_is_paused() 1.95 +{ 1.96 + return mozilla_sampler_is_paused(); 1.97 +} 1.98 + 1.99 +static inline 1.100 +void profiler_pause() 1.101 +{ 1.102 + mozilla_sampler_pause(); 1.103 +} 1.104 + 1.105 +static inline 1.106 +void profiler_resume() 1.107 +{ 1.108 + mozilla_sampler_resume(); 1.109 +} 1.110 + 1.111 +static inline 1.112 +ProfilerBacktrace* profiler_get_backtrace() 1.113 +{ 1.114 + return mozilla_sampler_get_backtrace(); 1.115 +} 1.116 + 1.117 +static inline 1.118 +void profiler_free_backtrace(ProfilerBacktrace* aBacktrace) 1.119 +{ 1.120 + mozilla_sampler_free_backtrace(aBacktrace); 1.121 +} 1.122 + 1.123 +static inline 1.124 +bool profiler_is_active() 1.125 +{ 1.126 + return mozilla_sampler_is_active(); 1.127 +} 1.128 + 1.129 +static inline 1.130 +void profiler_responsiveness(const mozilla::TimeStamp& aTime) 1.131 +{ 1.132 + mozilla_sampler_responsiveness(aTime); 1.133 +} 1.134 + 1.135 +static inline 1.136 +const double* profiler_get_responsiveness() 1.137 +{ 1.138 + return mozilla_sampler_get_responsiveness(); 1.139 +} 1.140 + 1.141 +static inline 1.142 +void profiler_set_frame_number(int frameNumber) 1.143 +{ 1.144 + return mozilla_sampler_frame_number(frameNumber); 1.145 +} 1.146 + 1.147 +static inline 1.148 +char* profiler_get_profile() 1.149 +{ 1.150 + return mozilla_sampler_get_profile(); 1.151 +} 1.152 + 1.153 +static inline 1.154 +JSObject* profiler_get_profile_jsobject(JSContext* aCx) 1.155 +{ 1.156 + return mozilla_sampler_get_profile_data(aCx); 1.157 +} 1.158 + 1.159 +static inline 1.160 +void profiler_save_profile_to_file(const char* aFilename) 1.161 +{ 1.162 + return mozilla_sampler_save_profile_to_file(aFilename); 1.163 +} 1.164 + 1.165 +static inline 1.166 +const char** profiler_get_features() 1.167 +{ 1.168 + return mozilla_sampler_get_features(); 1.169 +} 1.170 + 1.171 +static inline 1.172 +void profiler_print_location() 1.173 +{ 1.174 + if (!sps_version2()) { 1.175 + return mozilla_sampler_print_location1(); 1.176 + } else { 1.177 + return mozilla_sampler_print_location2(); 1.178 + } 1.179 +} 1.180 + 1.181 +static inline 1.182 +void profiler_lock() 1.183 +{ 1.184 + return mozilla_sampler_lock(); 1.185 +} 1.186 + 1.187 +static inline 1.188 +void profiler_unlock() 1.189 +{ 1.190 + return mozilla_sampler_unlock(); 1.191 +} 1.192 + 1.193 +static inline 1.194 +void profiler_register_thread(const char* name, void* stackTop) 1.195 +{ 1.196 + mozilla_sampler_register_thread(name, stackTop); 1.197 +} 1.198 + 1.199 +static inline 1.200 +void profiler_unregister_thread() 1.201 +{ 1.202 + mozilla_sampler_unregister_thread(); 1.203 +} 1.204 + 1.205 +static inline 1.206 +void profiler_sleep_start() 1.207 +{ 1.208 + mozilla_sampler_sleep_start(); 1.209 +} 1.210 + 1.211 +static inline 1.212 +void profiler_sleep_end() 1.213 +{ 1.214 + mozilla_sampler_sleep_end(); 1.215 +} 1.216 + 1.217 +static inline 1.218 +void profiler_js_operation_callback() 1.219 +{ 1.220 + PseudoStack *stack = tlsPseudoStack.get(); 1.221 + if (!stack) { 1.222 + return; 1.223 + } 1.224 + 1.225 + stack->jsOperationCallback(); 1.226 +} 1.227 + 1.228 +static inline 1.229 +double profiler_time() 1.230 +{ 1.231 + return mozilla_sampler_time(); 1.232 +} 1.233 + 1.234 +static inline 1.235 +double profiler_time(const mozilla::TimeStamp& aTime) 1.236 +{ 1.237 + return mozilla_sampler_time(aTime); 1.238 +} 1.239 + 1.240 +static inline 1.241 +bool profiler_in_privacy_mode() 1.242 +{ 1.243 + PseudoStack *stack = tlsPseudoStack.get(); 1.244 + if (!stack) { 1.245 + return false; 1.246 + } 1.247 + return stack->mPrivacyMode; 1.248 +} 1.249 + 1.250 +static inline void profiler_tracing(const char* aCategory, const char* aInfo, 1.251 + TracingMetadata aMetaData = TRACING_DEFAULT) 1.252 +{ 1.253 + if (!stack_key_initialized) 1.254 + return; 1.255 + 1.256 + // Don't insert a marker if we're not profiling to avoid 1.257 + // the heap copy (malloc). 1.258 + if (!profiler_is_active()) { 1.259 + return; 1.260 + } 1.261 + 1.262 + mozilla_sampler_tracing(aCategory, aInfo, aMetaData); 1.263 +} 1.264 + 1.265 +// Uncomment this to turn on systrace or build with 1.266 +// ac_add_options --enable-systace 1.267 +//#define MOZ_USE_SYSTRACE 1.268 +#ifdef MOZ_USE_SYSTRACE 1.269 +# define ATRACE_TAG ATRACE_TAG_GRAPHICS 1.270 +// We need HAVE_ANDROID_OS to be defined for Trace.h. 1.271 +// If its not set we will set it temporary and remove it. 1.272 +# ifndef HAVE_ANDROID_OS 1.273 +# define HAVE_ANDROID_OS 1.274 +# define REMOVE_HAVE_ANDROID_OS 1.275 +# endif 1.276 +# include <utils/Trace.h> 1.277 +# define MOZ_PLATFORM_TRACING ATRACE_CALL(); 1.278 +# ifdef REMOVE_HAVE_ANDROID_OS 1.279 +# undef HAVE_ANDROID_OS 1.280 +# undef REMOVE_HAVE_ANDROID_OS 1.281 +# endif 1.282 +#else 1.283 +# define MOZ_PLATFORM_TRACING 1.284 +#endif 1.285 + 1.286 +// we want the class and function name but can't easily get that using preprocessor macros 1.287 +// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters 1.288 + 1.289 +#define SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) id ## line 1.290 +#define SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, line) SAMPLER_APPEND_LINE_NUMBER_PASTE(id, line) 1.291 +#define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__) 1.292 + 1.293 +#define PROFILER_LABEL(name_space, info) MOZ_PLATFORM_TRACING mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__) 1.294 +#define PROFILER_LABEL_PRINTF(name_space, info, ...) MOZ_PLATFORM_TRACING mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__) 1.295 + 1.296 +#define PROFILER_MARKER(info) mozilla_sampler_add_marker(info) 1.297 +#define PROFILER_MARKER_PAYLOAD(info, payload) mozilla_sampler_add_marker(info, payload) 1.298 +#define PROFILER_MAIN_THREAD_MARKER(info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info) 1.299 + 1.300 +#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__) 1.301 +#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__) 1.302 + 1.303 + 1.304 +/* FIXME/bug 789667: memory constraints wouldn't much of a problem for 1.305 + * this small a sample buffer size, except that serializing the 1.306 + * profile data is extremely, unnecessarily memory intensive. */ 1.307 +#ifdef MOZ_WIDGET_GONK 1.308 +# define PLATFORM_LIKELY_MEMORY_CONSTRAINED 1.309 +#endif 1.310 + 1.311 +#if !defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) && !defined(ARCH_ARMV6) 1.312 +# define PROFILE_DEFAULT_ENTRY 1000000 1.313 +#else 1.314 +# define PROFILE_DEFAULT_ENTRY 100000 1.315 +#endif 1.316 + 1.317 +// In the case of profiler_get_backtrace we know that we only need enough space 1.318 +// for a single backtrace. 1.319 +#define GET_BACKTRACE_DEFAULT_ENTRY 1000 1.320 + 1.321 +#if defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) 1.322 +/* A 1ms sampling interval has been shown to be a large perf hit 1.323 + * (10fps) on memory-contrained (low-end) platforms, and additionally 1.324 + * to yield different results from the profiler. Where this is the 1.325 + * important case, b2g, there are also many gecko processes which 1.326 + * magnify these effects. */ 1.327 +# define PROFILE_DEFAULT_INTERVAL 10 1.328 +#elif defined(ANDROID) 1.329 +// We use a lower frequency on Android, in order to make things work 1.330 +// more smoothly on phones. This value can be adjusted later with 1.331 +// some libunwind optimizations. 1.332 +// In one sample measurement on Galaxy Nexus, out of about 700 backtraces, 1.333 +// 60 of them took more than 25ms, and the average and standard deviation 1.334 +// were 6.17ms and 9.71ms respectively. 1.335 + 1.336 +// For now since we don't support stackwalking let's use 1ms since it's fast 1.337 +// enough. 1.338 +#define PROFILE_DEFAULT_INTERVAL 1 1.339 +#else 1.340 +#define PROFILE_DEFAULT_INTERVAL 1 1.341 +#endif 1.342 +#define PROFILE_DEFAULT_FEATURES NULL 1.343 +#define PROFILE_DEFAULT_FEATURE_COUNT 0 1.344 + 1.345 +namespace mozilla { 1.346 + 1.347 +class MOZ_STACK_CLASS SamplerStackFrameRAII { 1.348 +public: 1.349 + // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then. 1.350 + SamplerStackFrameRAII(const char *aInfo, uint32_t line) { 1.351 + mHandle = mozilla_sampler_call_enter(aInfo, this, false, line); 1.352 + } 1.353 + ~SamplerStackFrameRAII() { 1.354 + mozilla_sampler_call_exit(mHandle); 1.355 + } 1.356 +private: 1.357 + void* mHandle; 1.358 +}; 1.359 + 1.360 +static const int SAMPLER_MAX_STRING = 128; 1.361 +class MOZ_STACK_CLASS SamplerStackFramePrintfRAII { 1.362 +public: 1.363 + // we only copy the strings at save time, so to take multiple parameters we'd need to copy them then. 1.364 + SamplerStackFramePrintfRAII(const char *aDefault, uint32_t line, const char *aFormat, ...) { 1.365 + if (profiler_is_active() && !profiler_in_privacy_mode()) { 1.366 + va_list args; 1.367 + va_start(args, aFormat); 1.368 + char buff[SAMPLER_MAX_STRING]; 1.369 + 1.370 + // We have to use seperate printf's because we're using 1.371 + // the vargs. 1.372 +#if _MSC_VER 1.373 + _vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args); 1.374 + _snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff); 1.375 +#else 1.376 + ::vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args); 1.377 + ::snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff); 1.378 +#endif 1.379 + mHandle = mozilla_sampler_call_enter(mDest, this, true, line); 1.380 + va_end(args); 1.381 + } else { 1.382 + mHandle = mozilla_sampler_call_enter(aDefault, this, false, line); 1.383 + } 1.384 + } 1.385 + ~SamplerStackFramePrintfRAII() { 1.386 + mozilla_sampler_call_exit(mHandle); 1.387 + } 1.388 +private: 1.389 + char mDest[SAMPLER_MAX_STRING]; 1.390 + void* mHandle; 1.391 +}; 1.392 + 1.393 +} //mozilla 1.394 + 1.395 +inline PseudoStack* mozilla_get_pseudo_stack(void) 1.396 +{ 1.397 + if (!stack_key_initialized) 1.398 + return nullptr; 1.399 + return tlsPseudoStack.get(); 1.400 +} 1.401 + 1.402 +inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress, 1.403 + bool aCopy, uint32_t line) 1.404 +{ 1.405 + // check if we've been initialized to avoid calling pthread_getspecific 1.406 + // with a null tlsStack which will return undefined results. 1.407 + if (!stack_key_initialized) 1.408 + return nullptr; 1.409 + 1.410 + PseudoStack *stack = tlsPseudoStack.get(); 1.411 + // we can't infer whether 'stack' has been initialized 1.412 + // based on the value of stack_key_intiailized because 1.413 + // 'stack' is only intialized when a thread is being 1.414 + // profiled. 1.415 + if (!stack) { 1.416 + return stack; 1.417 + } 1.418 + stack->push(aInfo, aFrameAddress, aCopy, line); 1.419 + 1.420 + // The handle is meant to support future changes 1.421 + // but for now it is simply use to save a call to 1.422 + // pthread_getspecific on exit. It also supports the 1.423 + // case where the sampler is initialized between 1.424 + // enter and exit. 1.425 + return stack; 1.426 +} 1.427 + 1.428 +inline void mozilla_sampler_call_exit(void *aHandle) 1.429 +{ 1.430 + if (!aHandle) 1.431 + return; 1.432 + 1.433 + PseudoStack *stack = (PseudoStack*)aHandle; 1.434 + stack->pop(); 1.435 +} 1.436 + 1.437 +void mozilla_sampler_add_marker(const char *aMarker, ProfilerMarkerPayload *aPayload); 1.438 + 1.439 +#endif /* ndef TOOLS_SPS_SAMPLER_H_ */