1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/platform.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,425 @@ 1.4 +// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. 1.5 +// 1.6 +// Redistribution and use in source and binary forms, with or without 1.7 +// modification, are permitted provided that the following conditions 1.8 +// are met: 1.9 +// * Redistributions of source code must retain the above copyright 1.10 +// notice, this list of conditions and the following disclaimer. 1.11 +// * Redistributions in binary form must reproduce the above copyright 1.12 +// notice, this list of conditions and the following disclaimer in 1.13 +// the documentation and/or other materials provided with the 1.14 +// distribution. 1.15 +// * Neither the name of Google, Inc. nor the names of its contributors 1.16 +// may be used to endorse or promote products derived from this 1.17 +// software without specific prior written permission. 1.18 +// 1.19 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.20 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.21 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1.22 +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 1.23 +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1.24 +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 1.25 +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 1.26 +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 1.27 +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 1.28 +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 1.29 +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.30 +// SUCH DAMAGE. 1.31 + 1.32 +#ifndef TOOLS_PLATFORM_H_ 1.33 +#define TOOLS_PLATFORM_H_ 1.34 + 1.35 +#ifdef ANDROID 1.36 +#include <android/log.h> 1.37 +#else 1.38 +#define __android_log_print(a, ...) 1.39 +#endif 1.40 + 1.41 +#ifdef XP_UNIX 1.42 +#include <pthread.h> 1.43 +#endif 1.44 + 1.45 +#include <stdint.h> 1.46 +#include <math.h> 1.47 +#include "mozilla/unused.h" 1.48 +#include "mozilla/TimeStamp.h" 1.49 +#include "mozilla/Mutex.h" 1.50 +#include "MainThreadUtils.h" 1.51 +#include "PlatformMacros.h" 1.52 +#include "v8-support.h" 1.53 +#include <vector> 1.54 + 1.55 +#ifdef XP_WIN 1.56 +#include <windows.h> 1.57 +#endif 1.58 + 1.59 +#define ASSERT(a) MOZ_ASSERT(a) 1.60 + 1.61 +bool moz_profiler_verbose(); 1.62 + 1.63 +#ifdef ANDROID 1.64 +# if defined(__arm__) || defined(__thumb__) 1.65 +# define ENABLE_SPS_LEAF_DATA 1.66 +# define ENABLE_ARM_LR_SAVING 1.67 +# endif 1.68 +# define LOG(text) \ 1.69 + do { if (moz_profiler_verbose()) \ 1.70 + __android_log_write(ANDROID_LOG_ERROR, "Profiler", text); \ 1.71 + } while (0) 1.72 +# define LOGF(format, ...) \ 1.73 + do { if (moz_profiler_verbose()) \ 1.74 + __android_log_print(ANDROID_LOG_ERROR, "Profiler", format, \ 1.75 + __VA_ARGS__); \ 1.76 + } while (0) 1.77 + 1.78 +#else 1.79 +# define LOG(text) \ 1.80 + do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: %s\n", text); \ 1.81 + } while (0) 1.82 +# define LOGF(format, ...) \ 1.83 + do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: " format \ 1.84 + "\n", __VA_ARGS__); \ 1.85 + } while (0) 1.86 + 1.87 +#endif 1.88 + 1.89 +#if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_LINUX) 1.90 +#define ENABLE_SPS_LEAF_DATA 1.91 +#endif 1.92 + 1.93 +extern mozilla::TimeStamp sStartTime; 1.94 + 1.95 +typedef uint8_t* Address; 1.96 + 1.97 +// ---------------------------------------------------------------------------- 1.98 +// Mutex 1.99 +// 1.100 +// Mutexes are used for serializing access to non-reentrant sections of code. 1.101 +// The implementations of mutex should allow for nested/recursive locking. 1.102 + 1.103 +class Mutex { 1.104 + public: 1.105 + virtual ~Mutex() {} 1.106 + 1.107 + // Locks the given mutex. If the mutex is currently unlocked, it becomes 1.108 + // locked and owned by the calling thread, and immediately. If the mutex 1.109 + // is already locked by another thread, suspends the calling thread until 1.110 + // the mutex is unlocked. 1.111 + virtual int Lock() = 0; 1.112 + 1.113 + // Unlocks the given mutex. The mutex is assumed to be locked and owned by 1.114 + // the calling thread on entrance. 1.115 + virtual int Unlock() = 0; 1.116 + 1.117 + // Tries to lock the given mutex. Returns whether the mutex was 1.118 + // successfully locked. 1.119 + virtual bool TryLock() = 0; 1.120 +}; 1.121 + 1.122 +// ---------------------------------------------------------------------------- 1.123 +// OS 1.124 +// 1.125 +// This class has static methods for the different platform specific 1.126 +// functions. Add methods here to cope with differences between the 1.127 +// supported platforms. 1.128 + 1.129 +class OS { 1.130 + public: 1.131 + 1.132 + // Sleep for a number of milliseconds. 1.133 + static void Sleep(const int milliseconds); 1.134 + 1.135 + // Sleep for a number of microseconds. 1.136 + static void SleepMicro(const int microseconds); 1.137 + 1.138 + // Called on startup to initialize platform specific things 1.139 + static void Startup(); 1.140 + 1.141 + private: 1.142 + static const int msPerSecond = 1000; 1.143 + 1.144 +}; 1.145 + 1.146 + 1.147 + 1.148 + 1.149 +// ---------------------------------------------------------------------------- 1.150 +// Thread 1.151 +// 1.152 +// Thread objects are used for creating and running threads. When the start() 1.153 +// method is called the new thread starts running the run() method in the new 1.154 +// thread. The Thread object should not be deallocated before the thread has 1.155 +// terminated. 1.156 + 1.157 +class Thread { 1.158 + public: 1.159 + // Create new thread. 1.160 + explicit Thread(const char* name); 1.161 + virtual ~Thread(); 1.162 + 1.163 + // Start new thread by calling the Run() method in the new thread. 1.164 + void Start(); 1.165 + 1.166 + void Join(); 1.167 + 1.168 + inline const char* name() const { 1.169 + return name_; 1.170 + } 1.171 + 1.172 + // Abstract method for run handler. 1.173 + virtual void Run() = 0; 1.174 + 1.175 + // The thread name length is limited to 16 based on Linux's implementation of 1.176 + // prctl(). 1.177 + static const int kMaxThreadNameLength = 16; 1.178 + 1.179 +#ifdef XP_WIN 1.180 + HANDLE thread_; 1.181 + typedef DWORD tid_t; 1.182 + tid_t thread_id_; 1.183 +#else 1.184 + typedef ::pid_t tid_t; 1.185 +#endif 1.186 +#if defined(XP_MACOSX) 1.187 + pthread_t thread_; 1.188 +#endif 1.189 + 1.190 + static tid_t GetCurrentId(); 1.191 + 1.192 + private: 1.193 + void set_name(const char *name); 1.194 + 1.195 + char name_[kMaxThreadNameLength]; 1.196 + int stack_size_; 1.197 + 1.198 + DISALLOW_COPY_AND_ASSIGN(Thread); 1.199 +}; 1.200 + 1.201 +// ---------------------------------------------------------------------------- 1.202 +// HAVE_NATIVE_UNWIND 1.203 +// 1.204 +// Pseudo backtraces are available on all platforms. Native 1.205 +// backtraces are available only on selected platforms. Breakpad is 1.206 +// the only supported native unwinder. HAVE_NATIVE_UNWIND is set at 1.207 +// build time to indicate whether native unwinding is possible on this 1.208 +// platform. The actual unwind mode currently in use is stored in 1.209 +// sUnwindMode. 1.210 + 1.211 +#undef HAVE_NATIVE_UNWIND 1.212 +#if defined(MOZ_PROFILING) \ 1.213 + && (defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \ 1.214 + || defined(SPS_PLAT_x86_linux) \ 1.215 + || defined(SPS_OS_windows) \ 1.216 + || defined(SPS_OS_darwin)) 1.217 +# define HAVE_NATIVE_UNWIND 1.218 +#endif 1.219 + 1.220 +/* Some values extracted at startup from environment variables, that 1.221 + control the behaviour of the breakpad unwinder. */ 1.222 +extern const char* PROFILER_MODE; 1.223 +extern const char* PROFILER_INTERVAL; 1.224 +extern const char* PROFILER_ENTRIES; 1.225 +extern const char* PROFILER_STACK; 1.226 +extern const char* PROFILER_FEATURES; 1.227 + 1.228 +void read_profiler_env_vars(); 1.229 +void profiler_usage(); 1.230 + 1.231 +// Helper methods to expose modifying profiler behavior 1.232 +bool set_profiler_mode(const char*); 1.233 +bool set_profiler_interval(const char*); 1.234 +bool set_profiler_entries(const char*); 1.235 +bool set_profiler_scan(const char*); 1.236 +bool is_native_unwinding_avail(); 1.237 + 1.238 +typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode; 1.239 +extern UnwMode sUnwindMode; /* what mode? */ 1.240 +extern int sUnwindInterval; /* in milliseconds */ 1.241 +extern int sUnwindStackScan; /* max # of dubious frames allowed */ 1.242 + 1.243 +extern int sProfileEntries; /* how many entries do we store? */ 1.244 + 1.245 +void set_tls_stack_top(void* stackTop); 1.246 + 1.247 +// ---------------------------------------------------------------------------- 1.248 +// Sampler 1.249 +// 1.250 +// A sampler periodically samples the state of the VM and optionally 1.251 +// (if used for profiling) the program counter and stack pointer for 1.252 +// the thread that created it. 1.253 + 1.254 +class PseudoStack; 1.255 +class ThreadProfile; 1.256 + 1.257 +// TickSample captures the information collected for each sample. 1.258 +class TickSample { 1.259 + public: 1.260 + TickSample() 1.261 + : 1.262 + pc(NULL), 1.263 + sp(NULL), 1.264 + fp(NULL), 1.265 +#ifdef ENABLE_ARM_LR_SAVING 1.266 + lr(NULL), 1.267 +#endif 1.268 + context(NULL), 1.269 + isSamplingCurrentThread(false) {} 1.270 + 1.271 + void PopulateContext(void* aContext); 1.272 + 1.273 + Address pc; // Instruction pointer. 1.274 + Address sp; // Stack pointer. 1.275 + Address fp; // Frame pointer. 1.276 +#ifdef ENABLE_ARM_LR_SAVING 1.277 + Address lr; // ARM link register 1.278 +#endif 1.279 + void* context; // The context from the signal handler, if available. On 1.280 + // Win32 this may contain the windows thread context. 1.281 + bool isSamplingCurrentThread; 1.282 + ThreadProfile* threadProfile; 1.283 + mozilla::TimeStamp timestamp; 1.284 +}; 1.285 + 1.286 +class ThreadInfo; 1.287 +class PlatformData; 1.288 +class TableTicker; 1.289 +class SyncProfile; 1.290 +class Sampler { 1.291 + public: 1.292 + // Initialize sampler. 1.293 + explicit Sampler(double interval, bool profiling, int entrySize); 1.294 + virtual ~Sampler(); 1.295 + 1.296 + double interval() const { return interval_; } 1.297 + 1.298 + // This method is called for each sampling period with the current 1.299 + // program counter. 1.300 + virtual void Tick(TickSample* sample) = 0; 1.301 + 1.302 + // Immediately captures the calling thread's call stack and returns it. 1.303 + virtual SyncProfile* GetBacktrace() = 0; 1.304 + 1.305 + // Request a save from a signal handler 1.306 + virtual void RequestSave() = 0; 1.307 + // Process any outstanding request outside a signal handler. 1.308 + virtual void HandleSaveRequest() = 0; 1.309 + 1.310 + // Start and stop sampler. 1.311 + void Start(); 1.312 + void Stop(); 1.313 + 1.314 + // Is the sampler used for profiling? 1.315 + bool IsProfiling() const { return profiling_; } 1.316 + 1.317 + // Whether the sampler is running (that is, consumes resources). 1.318 + bool IsActive() const { return active_; } 1.319 + 1.320 + // Low overhead way to stop the sampler from ticking 1.321 + bool IsPaused() const { return paused_; } 1.322 + void SetPaused(bool value) { NoBarrier_Store(&paused_, value); } 1.323 + 1.324 + virtual bool ProfileThreads() const = 0; 1.325 + 1.326 + int EntrySize() { return entrySize_; } 1.327 + 1.328 + // We can't new/delete the type safely without defining it 1.329 + // (-Wdelete-incomplete). Use these Alloc/Free functions instead. 1.330 + static PlatformData* AllocPlatformData(int aThreadId); 1.331 + static void FreePlatformData(PlatformData*); 1.332 + 1.333 + // If we move the backtracing code into the platform files we won't 1.334 + // need to have these hacks 1.335 +#ifdef XP_WIN 1.336 + // xxxehsan sucky hack :( 1.337 + static uintptr_t GetThreadHandle(PlatformData*); 1.338 +#endif 1.339 +#ifdef XP_MACOSX 1.340 + static pthread_t GetProfiledThread(PlatformData*); 1.341 +#endif 1.342 + 1.343 + static std::vector<ThreadInfo*> GetRegisteredThreads() { 1.344 + return *sRegisteredThreads; 1.345 + } 1.346 + 1.347 + static bool RegisterCurrentThread(const char* aName, 1.348 + PseudoStack* aPseudoStack, 1.349 + bool aIsMainThread, void* stackTop); 1.350 + static void UnregisterCurrentThread(); 1.351 + 1.352 + static void Startup(); 1.353 + // Should only be called on shutdown 1.354 + static void Shutdown(); 1.355 + 1.356 + static TableTicker* GetActiveSampler() { return sActiveSampler; } 1.357 + static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; } 1.358 + 1.359 + static mozilla::Mutex* sRegisteredThreadsMutex; 1.360 + 1.361 + static bool CanNotifyObservers() { 1.362 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) 1.363 + // Android ANR reporter uses the profiler off the main thread 1.364 + return NS_IsMainThread(); 1.365 +#else 1.366 + MOZ_ASSERT(NS_IsMainThread()); 1.367 + return true; 1.368 +#endif 1.369 + } 1.370 + 1.371 + protected: 1.372 + static std::vector<ThreadInfo*>* sRegisteredThreads; 1.373 + static TableTicker* sActiveSampler; 1.374 + 1.375 + private: 1.376 + void SetActive(bool value) { NoBarrier_Store(&active_, value); } 1.377 + 1.378 + const double interval_; 1.379 + const bool profiling_; 1.380 + Atomic32 paused_; 1.381 + Atomic32 active_; 1.382 + const int entrySize_; 1.383 + 1.384 + // Refactor me! 1.385 +#if defined(SPS_OS_linux) || defined(SPS_OS_android) 1.386 + bool signal_handler_installed_; 1.387 + struct sigaction old_sigprof_signal_handler_; 1.388 + struct sigaction old_sigsave_signal_handler_; 1.389 + bool signal_sender_launched_; 1.390 + pthread_t signal_sender_thread_; 1.391 +#endif 1.392 +}; 1.393 + 1.394 +class ThreadInfo { 1.395 + public: 1.396 + ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack, void* aStackTop) 1.397 + : mName(strdup(aName)) 1.398 + , mThreadId(aThreadId) 1.399 + , mIsMainThread(aIsMainThread) 1.400 + , mPseudoStack(aPseudoStack) 1.401 + , mPlatformData(Sampler::AllocPlatformData(aThreadId)) 1.402 + , mProfile(NULL) 1.403 + , mStackTop(aStackTop) {} 1.404 + 1.405 + virtual ~ThreadInfo(); 1.406 + 1.407 + const char* Name() const { return mName; } 1.408 + int ThreadId() const { return mThreadId; } 1.409 + 1.410 + bool IsMainThread() const { return mIsMainThread; } 1.411 + PseudoStack* Stack() const { return mPseudoStack; } 1.412 + 1.413 + void SetProfile(ThreadProfile* aProfile) { mProfile = aProfile; } 1.414 + ThreadProfile* Profile() const { return mProfile; } 1.415 + 1.416 + PlatformData* GetPlatformData() const { return mPlatformData; } 1.417 + void* StackTop() const { return mStackTop; } 1.418 + private: 1.419 + char* mName; 1.420 + int mThreadId; 1.421 + const bool mIsMainThread; 1.422 + PseudoStack* mPseudoStack; 1.423 + PlatformData* mPlatformData; 1.424 + ThreadProfile* mProfile; 1.425 + void* const mStackTop; 1.426 +}; 1.427 + 1.428 +#endif /* ndef TOOLS_PLATFORM_H_ */