tools/profiler/platform.h

changeset 0
6474c204b198
     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_ */

mercurial