diff -r 000000000000 -r 6474c204b198 tools/profiler/platform.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/profiler/platform.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,425 @@ +// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google, Inc. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. + +#ifndef TOOLS_PLATFORM_H_ +#define TOOLS_PLATFORM_H_ + +#ifdef ANDROID +#include +#else +#define __android_log_print(a, ...) +#endif + +#ifdef XP_UNIX +#include +#endif + +#include +#include +#include "mozilla/unused.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/Mutex.h" +#include "MainThreadUtils.h" +#include "PlatformMacros.h" +#include "v8-support.h" +#include + +#ifdef XP_WIN +#include +#endif + +#define ASSERT(a) MOZ_ASSERT(a) + +bool moz_profiler_verbose(); + +#ifdef ANDROID +# if defined(__arm__) || defined(__thumb__) +# define ENABLE_SPS_LEAF_DATA +# define ENABLE_ARM_LR_SAVING +# endif +# define LOG(text) \ + do { if (moz_profiler_verbose()) \ + __android_log_write(ANDROID_LOG_ERROR, "Profiler", text); \ + } while (0) +# define LOGF(format, ...) \ + do { if (moz_profiler_verbose()) \ + __android_log_print(ANDROID_LOG_ERROR, "Profiler", format, \ + __VA_ARGS__); \ + } while (0) + +#else +# define LOG(text) \ + do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: %s\n", text); \ + } while (0) +# define LOGF(format, ...) \ + do { if (moz_profiler_verbose()) fprintf(stderr, "Profiler: " format \ + "\n", __VA_ARGS__); \ + } while (0) + +#endif + +#if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_LINUX) +#define ENABLE_SPS_LEAF_DATA +#endif + +extern mozilla::TimeStamp sStartTime; + +typedef uint8_t* Address; + +// ---------------------------------------------------------------------------- +// Mutex +// +// Mutexes are used for serializing access to non-reentrant sections of code. +// The implementations of mutex should allow for nested/recursive locking. + +class Mutex { + public: + virtual ~Mutex() {} + + // Locks the given mutex. If the mutex is currently unlocked, it becomes + // locked and owned by the calling thread, and immediately. If the mutex + // is already locked by another thread, suspends the calling thread until + // the mutex is unlocked. + virtual int Lock() = 0; + + // Unlocks the given mutex. The mutex is assumed to be locked and owned by + // the calling thread on entrance. + virtual int Unlock() = 0; + + // Tries to lock the given mutex. Returns whether the mutex was + // successfully locked. + virtual bool TryLock() = 0; +}; + +// ---------------------------------------------------------------------------- +// OS +// +// This class has static methods for the different platform specific +// functions. Add methods here to cope with differences between the +// supported platforms. + +class OS { + public: + + // Sleep for a number of milliseconds. + static void Sleep(const int milliseconds); + + // Sleep for a number of microseconds. + static void SleepMicro(const int microseconds); + + // Called on startup to initialize platform specific things + static void Startup(); + + private: + static const int msPerSecond = 1000; + +}; + + + + +// ---------------------------------------------------------------------------- +// Thread +// +// Thread objects are used for creating and running threads. When the start() +// method is called the new thread starts running the run() method in the new +// thread. The Thread object should not be deallocated before the thread has +// terminated. + +class Thread { + public: + // Create new thread. + explicit Thread(const char* name); + virtual ~Thread(); + + // Start new thread by calling the Run() method in the new thread. + void Start(); + + void Join(); + + inline const char* name() const { + return name_; + } + + // Abstract method for run handler. + virtual void Run() = 0; + + // The thread name length is limited to 16 based on Linux's implementation of + // prctl(). + static const int kMaxThreadNameLength = 16; + +#ifdef XP_WIN + HANDLE thread_; + typedef DWORD tid_t; + tid_t thread_id_; +#else + typedef ::pid_t tid_t; +#endif +#if defined(XP_MACOSX) + pthread_t thread_; +#endif + + static tid_t GetCurrentId(); + + private: + void set_name(const char *name); + + char name_[kMaxThreadNameLength]; + int stack_size_; + + DISALLOW_COPY_AND_ASSIGN(Thread); +}; + +// ---------------------------------------------------------------------------- +// HAVE_NATIVE_UNWIND +// +// Pseudo backtraces are available on all platforms. Native +// backtraces are available only on selected platforms. Breakpad is +// the only supported native unwinder. HAVE_NATIVE_UNWIND is set at +// build time to indicate whether native unwinding is possible on this +// platform. The actual unwind mode currently in use is stored in +// sUnwindMode. + +#undef HAVE_NATIVE_UNWIND +#if defined(MOZ_PROFILING) \ + && (defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \ + || defined(SPS_PLAT_x86_linux) \ + || defined(SPS_OS_windows) \ + || defined(SPS_OS_darwin)) +# define HAVE_NATIVE_UNWIND +#endif + +/* Some values extracted at startup from environment variables, that + control the behaviour of the breakpad unwinder. */ +extern const char* PROFILER_MODE; +extern const char* PROFILER_INTERVAL; +extern const char* PROFILER_ENTRIES; +extern const char* PROFILER_STACK; +extern const char* PROFILER_FEATURES; + +void read_profiler_env_vars(); +void profiler_usage(); + +// Helper methods to expose modifying profiler behavior +bool set_profiler_mode(const char*); +bool set_profiler_interval(const char*); +bool set_profiler_entries(const char*); +bool set_profiler_scan(const char*); +bool is_native_unwinding_avail(); + +typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode; +extern UnwMode sUnwindMode; /* what mode? */ +extern int sUnwindInterval; /* in milliseconds */ +extern int sUnwindStackScan; /* max # of dubious frames allowed */ + +extern int sProfileEntries; /* how many entries do we store? */ + +void set_tls_stack_top(void* stackTop); + +// ---------------------------------------------------------------------------- +// Sampler +// +// A sampler periodically samples the state of the VM and optionally +// (if used for profiling) the program counter and stack pointer for +// the thread that created it. + +class PseudoStack; +class ThreadProfile; + +// TickSample captures the information collected for each sample. +class TickSample { + public: + TickSample() + : + pc(NULL), + sp(NULL), + fp(NULL), +#ifdef ENABLE_ARM_LR_SAVING + lr(NULL), +#endif + context(NULL), + isSamplingCurrentThread(false) {} + + void PopulateContext(void* aContext); + + Address pc; // Instruction pointer. + Address sp; // Stack pointer. + Address fp; // Frame pointer. +#ifdef ENABLE_ARM_LR_SAVING + Address lr; // ARM link register +#endif + void* context; // The context from the signal handler, if available. On + // Win32 this may contain the windows thread context. + bool isSamplingCurrentThread; + ThreadProfile* threadProfile; + mozilla::TimeStamp timestamp; +}; + +class ThreadInfo; +class PlatformData; +class TableTicker; +class SyncProfile; +class Sampler { + public: + // Initialize sampler. + explicit Sampler(double interval, bool profiling, int entrySize); + virtual ~Sampler(); + + double interval() const { return interval_; } + + // This method is called for each sampling period with the current + // program counter. + virtual void Tick(TickSample* sample) = 0; + + // Immediately captures the calling thread's call stack and returns it. + virtual SyncProfile* GetBacktrace() = 0; + + // Request a save from a signal handler + virtual void RequestSave() = 0; + // Process any outstanding request outside a signal handler. + virtual void HandleSaveRequest() = 0; + + // Start and stop sampler. + void Start(); + void Stop(); + + // Is the sampler used for profiling? + bool IsProfiling() const { return profiling_; } + + // Whether the sampler is running (that is, consumes resources). + bool IsActive() const { return active_; } + + // Low overhead way to stop the sampler from ticking + bool IsPaused() const { return paused_; } + void SetPaused(bool value) { NoBarrier_Store(&paused_, value); } + + virtual bool ProfileThreads() const = 0; + + int EntrySize() { return entrySize_; } + + // We can't new/delete the type safely without defining it + // (-Wdelete-incomplete). Use these Alloc/Free functions instead. + static PlatformData* AllocPlatformData(int aThreadId); + static void FreePlatformData(PlatformData*); + + // If we move the backtracing code into the platform files we won't + // need to have these hacks +#ifdef XP_WIN + // xxxehsan sucky hack :( + static uintptr_t GetThreadHandle(PlatformData*); +#endif +#ifdef XP_MACOSX + static pthread_t GetProfiledThread(PlatformData*); +#endif + + static std::vector GetRegisteredThreads() { + return *sRegisteredThreads; + } + + static bool RegisterCurrentThread(const char* aName, + PseudoStack* aPseudoStack, + bool aIsMainThread, void* stackTop); + static void UnregisterCurrentThread(); + + static void Startup(); + // Should only be called on shutdown + static void Shutdown(); + + static TableTicker* GetActiveSampler() { return sActiveSampler; } + static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; } + + static mozilla::Mutex* sRegisteredThreadsMutex; + + static bool CanNotifyObservers() { +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) + // Android ANR reporter uses the profiler off the main thread + return NS_IsMainThread(); +#else + MOZ_ASSERT(NS_IsMainThread()); + return true; +#endif + } + + protected: + static std::vector* sRegisteredThreads; + static TableTicker* sActiveSampler; + + private: + void SetActive(bool value) { NoBarrier_Store(&active_, value); } + + const double interval_; + const bool profiling_; + Atomic32 paused_; + Atomic32 active_; + const int entrySize_; + + // Refactor me! +#if defined(SPS_OS_linux) || defined(SPS_OS_android) + bool signal_handler_installed_; + struct sigaction old_sigprof_signal_handler_; + struct sigaction old_sigsave_signal_handler_; + bool signal_sender_launched_; + pthread_t signal_sender_thread_; +#endif +}; + +class ThreadInfo { + public: + ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack, void* aStackTop) + : mName(strdup(aName)) + , mThreadId(aThreadId) + , mIsMainThread(aIsMainThread) + , mPseudoStack(aPseudoStack) + , mPlatformData(Sampler::AllocPlatformData(aThreadId)) + , mProfile(NULL) + , mStackTop(aStackTop) {} + + virtual ~ThreadInfo(); + + const char* Name() const { return mName; } + int ThreadId() const { return mThreadId; } + + bool IsMainThread() const { return mIsMainThread; } + PseudoStack* Stack() const { return mPseudoStack; } + + void SetProfile(ThreadProfile* aProfile) { mProfile = aProfile; } + ThreadProfile* Profile() const { return mProfile; } + + PlatformData* GetPlatformData() const { return mPlatformData; } + void* StackTop() const { return mStackTop; } + private: + char* mName; + int mThreadId; + const bool mIsMainThread; + PseudoStack* mPseudoStack; + PlatformData* mPlatformData; + ThreadProfile* mProfile; + void* const mStackTop; +}; + +#endif /* ndef TOOLS_PLATFORM_H_ */