tools/profiler/platform.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
michael@0 2 //
michael@0 3 // Redistribution and use in source and binary forms, with or without
michael@0 4 // modification, are permitted provided that the following conditions
michael@0 5 // are met:
michael@0 6 // * Redistributions of source code must retain the above copyright
michael@0 7 // notice, this list of conditions and the following disclaimer.
michael@0 8 // * Redistributions in binary form must reproduce the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer in
michael@0 10 // the documentation and/or other materials provided with the
michael@0 11 // distribution.
michael@0 12 // * Neither the name of Google, Inc. nor the names of its contributors
michael@0 13 // may be used to endorse or promote products derived from this
michael@0 14 // software without specific prior written permission.
michael@0 15 //
michael@0 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
michael@0 19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
michael@0 20 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
michael@0 21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
michael@0 22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
michael@0 23 // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
michael@0 24 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
michael@0 25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
michael@0 26 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@0 27 // SUCH DAMAGE.
michael@0 28
michael@0 29 #ifndef TOOLS_PLATFORM_H_
michael@0 30 #define TOOLS_PLATFORM_H_
michael@0 31
michael@0 32 #ifdef ANDROID
michael@0 33 #include <android/log.h>
michael@0 34 #else
michael@0 35 #define __android_log_print(a, ...)
michael@0 36 #endif
michael@0 37
michael@0 38 #ifdef XP_UNIX
michael@0 39 #include <pthread.h>
michael@0 40 #endif
michael@0 41
michael@0 42 #include <stdint.h>
michael@0 43 #include <math.h>
michael@0 44 #include "mozilla/unused.h"
michael@0 45 #include "mozilla/TimeStamp.h"
michael@0 46 #include "mozilla/Mutex.h"
michael@0 47 #include "MainThreadUtils.h"
michael@0 48 #include "PlatformMacros.h"
michael@0 49 #include "v8-support.h"
michael@0 50 #include <vector>
michael@0 51
michael@0 52 #ifdef XP_WIN
michael@0 53 #include <windows.h>
michael@0 54 #endif
michael@0 55
michael@0 56 #define ASSERT(a) MOZ_ASSERT(a)
michael@0 57
michael@0 58 bool moz_profiler_verbose();
michael@0 59
michael@0 60 #ifdef ANDROID
michael@0 61 # if defined(__arm__) || defined(__thumb__)
michael@0 62 # define ENABLE_SPS_LEAF_DATA
michael@0 63 # define ENABLE_ARM_LR_SAVING
michael@0 64 # endif
michael@0 65 # define LOG(text) \
michael@0 66 do { if (moz_profiler_verbose()) \
michael@0 67 __android_log_write(ANDROID_LOG_ERROR, "Profiler", text); \
michael@0 68 } while (0)
michael@0 69 # define LOGF(format, ...) \
michael@0 70 do { if (moz_profiler_verbose()) \
michael@0 71 __android_log_print(ANDROID_LOG_ERROR, "Profiler", format, \
michael@0 72 __VA_ARGS__); \
michael@0 73 } while (0)
michael@0 74
michael@0 75 #else
michael@0 76 # define LOG(text) \
michael@0 77 do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: %s\n", text); \
michael@0 78 } while (0)
michael@0 79 # define LOGF(format, ...) \
michael@0 80 do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: " format \
michael@0 81 "\n", __VA_ARGS__); \
michael@0 82 } while (0)
michael@0 83
michael@0 84 #endif
michael@0 85
michael@0 86 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_LINUX)
michael@0 87 #define ENABLE_SPS_LEAF_DATA
michael@0 88 #endif
michael@0 89
michael@0 90 extern mozilla::TimeStamp sStartTime;
michael@0 91
michael@0 92 typedef uint8_t* Address;
michael@0 93
michael@0 94 // ----------------------------------------------------------------------------
michael@0 95 // Mutex
michael@0 96 //
michael@0 97 // Mutexes are used for serializing access to non-reentrant sections of code.
michael@0 98 // The implementations of mutex should allow for nested/recursive locking.
michael@0 99
michael@0 100 class Mutex {
michael@0 101 public:
michael@0 102 virtual ~Mutex() {}
michael@0 103
michael@0 104 // Locks the given mutex. If the mutex is currently unlocked, it becomes
michael@0 105 // locked and owned by the calling thread, and immediately. If the mutex
michael@0 106 // is already locked by another thread, suspends the calling thread until
michael@0 107 // the mutex is unlocked.
michael@0 108 virtual int Lock() = 0;
michael@0 109
michael@0 110 // Unlocks the given mutex. The mutex is assumed to be locked and owned by
michael@0 111 // the calling thread on entrance.
michael@0 112 virtual int Unlock() = 0;
michael@0 113
michael@0 114 // Tries to lock the given mutex. Returns whether the mutex was
michael@0 115 // successfully locked.
michael@0 116 virtual bool TryLock() = 0;
michael@0 117 };
michael@0 118
michael@0 119 // ----------------------------------------------------------------------------
michael@0 120 // OS
michael@0 121 //
michael@0 122 // This class has static methods for the different platform specific
michael@0 123 // functions. Add methods here to cope with differences between the
michael@0 124 // supported platforms.
michael@0 125
michael@0 126 class OS {
michael@0 127 public:
michael@0 128
michael@0 129 // Sleep for a number of milliseconds.
michael@0 130 static void Sleep(const int milliseconds);
michael@0 131
michael@0 132 // Sleep for a number of microseconds.
michael@0 133 static void SleepMicro(const int microseconds);
michael@0 134
michael@0 135 // Called on startup to initialize platform specific things
michael@0 136 static void Startup();
michael@0 137
michael@0 138 private:
michael@0 139 static const int msPerSecond = 1000;
michael@0 140
michael@0 141 };
michael@0 142
michael@0 143
michael@0 144
michael@0 145
michael@0 146 // ----------------------------------------------------------------------------
michael@0 147 // Thread
michael@0 148 //
michael@0 149 // Thread objects are used for creating and running threads. When the start()
michael@0 150 // method is called the new thread starts running the run() method in the new
michael@0 151 // thread. The Thread object should not be deallocated before the thread has
michael@0 152 // terminated.
michael@0 153
michael@0 154 class Thread {
michael@0 155 public:
michael@0 156 // Create new thread.
michael@0 157 explicit Thread(const char* name);
michael@0 158 virtual ~Thread();
michael@0 159
michael@0 160 // Start new thread by calling the Run() method in the new thread.
michael@0 161 void Start();
michael@0 162
michael@0 163 void Join();
michael@0 164
michael@0 165 inline const char* name() const {
michael@0 166 return name_;
michael@0 167 }
michael@0 168
michael@0 169 // Abstract method for run handler.
michael@0 170 virtual void Run() = 0;
michael@0 171
michael@0 172 // The thread name length is limited to 16 based on Linux's implementation of
michael@0 173 // prctl().
michael@0 174 static const int kMaxThreadNameLength = 16;
michael@0 175
michael@0 176 #ifdef XP_WIN
michael@0 177 HANDLE thread_;
michael@0 178 typedef DWORD tid_t;
michael@0 179 tid_t thread_id_;
michael@0 180 #else
michael@0 181 typedef ::pid_t tid_t;
michael@0 182 #endif
michael@0 183 #if defined(XP_MACOSX)
michael@0 184 pthread_t thread_;
michael@0 185 #endif
michael@0 186
michael@0 187 static tid_t GetCurrentId();
michael@0 188
michael@0 189 private:
michael@0 190 void set_name(const char *name);
michael@0 191
michael@0 192 char name_[kMaxThreadNameLength];
michael@0 193 int stack_size_;
michael@0 194
michael@0 195 DISALLOW_COPY_AND_ASSIGN(Thread);
michael@0 196 };
michael@0 197
michael@0 198 // ----------------------------------------------------------------------------
michael@0 199 // HAVE_NATIVE_UNWIND
michael@0 200 //
michael@0 201 // Pseudo backtraces are available on all platforms. Native
michael@0 202 // backtraces are available only on selected platforms. Breakpad is
michael@0 203 // the only supported native unwinder. HAVE_NATIVE_UNWIND is set at
michael@0 204 // build time to indicate whether native unwinding is possible on this
michael@0 205 // platform. The actual unwind mode currently in use is stored in
michael@0 206 // sUnwindMode.
michael@0 207
michael@0 208 #undef HAVE_NATIVE_UNWIND
michael@0 209 #if defined(MOZ_PROFILING) \
michael@0 210 && (defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
michael@0 211 || defined(SPS_PLAT_x86_linux) \
michael@0 212 || defined(SPS_OS_windows) \
michael@0 213 || defined(SPS_OS_darwin))
michael@0 214 # define HAVE_NATIVE_UNWIND
michael@0 215 #endif
michael@0 216
michael@0 217 /* Some values extracted at startup from environment variables, that
michael@0 218 control the behaviour of the breakpad unwinder. */
michael@0 219 extern const char* PROFILER_MODE;
michael@0 220 extern const char* PROFILER_INTERVAL;
michael@0 221 extern const char* PROFILER_ENTRIES;
michael@0 222 extern const char* PROFILER_STACK;
michael@0 223 extern const char* PROFILER_FEATURES;
michael@0 224
michael@0 225 void read_profiler_env_vars();
michael@0 226 void profiler_usage();
michael@0 227
michael@0 228 // Helper methods to expose modifying profiler behavior
michael@0 229 bool set_profiler_mode(const char*);
michael@0 230 bool set_profiler_interval(const char*);
michael@0 231 bool set_profiler_entries(const char*);
michael@0 232 bool set_profiler_scan(const char*);
michael@0 233 bool is_native_unwinding_avail();
michael@0 234
michael@0 235 typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode;
michael@0 236 extern UnwMode sUnwindMode; /* what mode? */
michael@0 237 extern int sUnwindInterval; /* in milliseconds */
michael@0 238 extern int sUnwindStackScan; /* max # of dubious frames allowed */
michael@0 239
michael@0 240 extern int sProfileEntries; /* how many entries do we store? */
michael@0 241
michael@0 242 void set_tls_stack_top(void* stackTop);
michael@0 243
michael@0 244 // ----------------------------------------------------------------------------
michael@0 245 // Sampler
michael@0 246 //
michael@0 247 // A sampler periodically samples the state of the VM and optionally
michael@0 248 // (if used for profiling) the program counter and stack pointer for
michael@0 249 // the thread that created it.
michael@0 250
michael@0 251 class PseudoStack;
michael@0 252 class ThreadProfile;
michael@0 253
michael@0 254 // TickSample captures the information collected for each sample.
michael@0 255 class TickSample {
michael@0 256 public:
michael@0 257 TickSample()
michael@0 258 :
michael@0 259 pc(NULL),
michael@0 260 sp(NULL),
michael@0 261 fp(NULL),
michael@0 262 #ifdef ENABLE_ARM_LR_SAVING
michael@0 263 lr(NULL),
michael@0 264 #endif
michael@0 265 context(NULL),
michael@0 266 isSamplingCurrentThread(false) {}
michael@0 267
michael@0 268 void PopulateContext(void* aContext);
michael@0 269
michael@0 270 Address pc; // Instruction pointer.
michael@0 271 Address sp; // Stack pointer.
michael@0 272 Address fp; // Frame pointer.
michael@0 273 #ifdef ENABLE_ARM_LR_SAVING
michael@0 274 Address lr; // ARM link register
michael@0 275 #endif
michael@0 276 void* context; // The context from the signal handler, if available. On
michael@0 277 // Win32 this may contain the windows thread context.
michael@0 278 bool isSamplingCurrentThread;
michael@0 279 ThreadProfile* threadProfile;
michael@0 280 mozilla::TimeStamp timestamp;
michael@0 281 };
michael@0 282
michael@0 283 class ThreadInfo;
michael@0 284 class PlatformData;
michael@0 285 class TableTicker;
michael@0 286 class SyncProfile;
michael@0 287 class Sampler {
michael@0 288 public:
michael@0 289 // Initialize sampler.
michael@0 290 explicit Sampler(double interval, bool profiling, int entrySize);
michael@0 291 virtual ~Sampler();
michael@0 292
michael@0 293 double interval() const { return interval_; }
michael@0 294
michael@0 295 // This method is called for each sampling period with the current
michael@0 296 // program counter.
michael@0 297 virtual void Tick(TickSample* sample) = 0;
michael@0 298
michael@0 299 // Immediately captures the calling thread's call stack and returns it.
michael@0 300 virtual SyncProfile* GetBacktrace() = 0;
michael@0 301
michael@0 302 // Request a save from a signal handler
michael@0 303 virtual void RequestSave() = 0;
michael@0 304 // Process any outstanding request outside a signal handler.
michael@0 305 virtual void HandleSaveRequest() = 0;
michael@0 306
michael@0 307 // Start and stop sampler.
michael@0 308 void Start();
michael@0 309 void Stop();
michael@0 310
michael@0 311 // Is the sampler used for profiling?
michael@0 312 bool IsProfiling() const { return profiling_; }
michael@0 313
michael@0 314 // Whether the sampler is running (that is, consumes resources).
michael@0 315 bool IsActive() const { return active_; }
michael@0 316
michael@0 317 // Low overhead way to stop the sampler from ticking
michael@0 318 bool IsPaused() const { return paused_; }
michael@0 319 void SetPaused(bool value) { NoBarrier_Store(&paused_, value); }
michael@0 320
michael@0 321 virtual bool ProfileThreads() const = 0;
michael@0 322
michael@0 323 int EntrySize() { return entrySize_; }
michael@0 324
michael@0 325 // We can't new/delete the type safely without defining it
michael@0 326 // (-Wdelete-incomplete). Use these Alloc/Free functions instead.
michael@0 327 static PlatformData* AllocPlatformData(int aThreadId);
michael@0 328 static void FreePlatformData(PlatformData*);
michael@0 329
michael@0 330 // If we move the backtracing code into the platform files we won't
michael@0 331 // need to have these hacks
michael@0 332 #ifdef XP_WIN
michael@0 333 // xxxehsan sucky hack :(
michael@0 334 static uintptr_t GetThreadHandle(PlatformData*);
michael@0 335 #endif
michael@0 336 #ifdef XP_MACOSX
michael@0 337 static pthread_t GetProfiledThread(PlatformData*);
michael@0 338 #endif
michael@0 339
michael@0 340 static std::vector<ThreadInfo*> GetRegisteredThreads() {
michael@0 341 return *sRegisteredThreads;
michael@0 342 }
michael@0 343
michael@0 344 static bool RegisterCurrentThread(const char* aName,
michael@0 345 PseudoStack* aPseudoStack,
michael@0 346 bool aIsMainThread, void* stackTop);
michael@0 347 static void UnregisterCurrentThread();
michael@0 348
michael@0 349 static void Startup();
michael@0 350 // Should only be called on shutdown
michael@0 351 static void Shutdown();
michael@0 352
michael@0 353 static TableTicker* GetActiveSampler() { return sActiveSampler; }
michael@0 354 static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; }
michael@0 355
michael@0 356 static mozilla::Mutex* sRegisteredThreadsMutex;
michael@0 357
michael@0 358 static bool CanNotifyObservers() {
michael@0 359 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
michael@0 360 // Android ANR reporter uses the profiler off the main thread
michael@0 361 return NS_IsMainThread();
michael@0 362 #else
michael@0 363 MOZ_ASSERT(NS_IsMainThread());
michael@0 364 return true;
michael@0 365 #endif
michael@0 366 }
michael@0 367
michael@0 368 protected:
michael@0 369 static std::vector<ThreadInfo*>* sRegisteredThreads;
michael@0 370 static TableTicker* sActiveSampler;
michael@0 371
michael@0 372 private:
michael@0 373 void SetActive(bool value) { NoBarrier_Store(&active_, value); }
michael@0 374
michael@0 375 const double interval_;
michael@0 376 const bool profiling_;
michael@0 377 Atomic32 paused_;
michael@0 378 Atomic32 active_;
michael@0 379 const int entrySize_;
michael@0 380
michael@0 381 // Refactor me!
michael@0 382 #if defined(SPS_OS_linux) || defined(SPS_OS_android)
michael@0 383 bool signal_handler_installed_;
michael@0 384 struct sigaction old_sigprof_signal_handler_;
michael@0 385 struct sigaction old_sigsave_signal_handler_;
michael@0 386 bool signal_sender_launched_;
michael@0 387 pthread_t signal_sender_thread_;
michael@0 388 #endif
michael@0 389 };
michael@0 390
michael@0 391 class ThreadInfo {
michael@0 392 public:
michael@0 393 ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack, void* aStackTop)
michael@0 394 : mName(strdup(aName))
michael@0 395 , mThreadId(aThreadId)
michael@0 396 , mIsMainThread(aIsMainThread)
michael@0 397 , mPseudoStack(aPseudoStack)
michael@0 398 , mPlatformData(Sampler::AllocPlatformData(aThreadId))
michael@0 399 , mProfile(NULL)
michael@0 400 , mStackTop(aStackTop) {}
michael@0 401
michael@0 402 virtual ~ThreadInfo();
michael@0 403
michael@0 404 const char* Name() const { return mName; }
michael@0 405 int ThreadId() const { return mThreadId; }
michael@0 406
michael@0 407 bool IsMainThread() const { return mIsMainThread; }
michael@0 408 PseudoStack* Stack() const { return mPseudoStack; }
michael@0 409
michael@0 410 void SetProfile(ThreadProfile* aProfile) { mProfile = aProfile; }
michael@0 411 ThreadProfile* Profile() const { return mProfile; }
michael@0 412
michael@0 413 PlatformData* GetPlatformData() const { return mPlatformData; }
michael@0 414 void* StackTop() const { return mStackTop; }
michael@0 415 private:
michael@0 416 char* mName;
michael@0 417 int mThreadId;
michael@0 418 const bool mIsMainThread;
michael@0 419 PseudoStack* mPseudoStack;
michael@0 420 PlatformData* mPlatformData;
michael@0 421 ThreadProfile* mProfile;
michael@0 422 void* const mStackTop;
michael@0 423 };
michael@0 424
michael@0 425 #endif /* ndef TOOLS_PLATFORM_H_ */

mercurial