2011-08-26 17:05:37 -07:00
|
|
|
// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
|
2012-11-19 11:02:32 -08:00
|
|
|
//
|
|
|
|
// 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.
|
2011-08-26 17:05:37 -07:00
|
|
|
|
2013-03-10 15:00:23 -07:00
|
|
|
#ifndef TOOLS_PLATFORM_H_
|
|
|
|
#define TOOLS_PLATFORM_H_
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
#ifdef ANDROID
|
|
|
|
#include <android/log.h>
|
|
|
|
#else
|
|
|
|
#define __android_log_print(a, ...)
|
|
|
|
#endif
|
|
|
|
|
2012-02-29 19:56:43 -08:00
|
|
|
#include "mozilla/StandardInteger.h"
|
2011-08-26 17:05:37 -07:00
|
|
|
#include "mozilla/Util.h"
|
|
|
|
#include "mozilla/unused.h"
|
2011-12-24 09:11:26 -08:00
|
|
|
#include "mozilla/TimeStamp.h"
|
2013-03-25 14:57:28 -07:00
|
|
|
#include "PlatformMacros.h"
|
2011-12-01 07:06:20 -08:00
|
|
|
#include "v8-support.h"
|
2011-08-26 17:05:37 -07:00
|
|
|
#include <vector>
|
2013-04-06 01:45:30 -07:00
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
#define ASSERT(a) MOZ_ASSERT(a)
|
2013-04-06 01:45:30 -07:00
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
#ifdef ANDROID
|
2013-04-06 01:45:30 -07:00
|
|
|
# if defined(__arm__) || defined(__thumb__)
|
|
|
|
# define ENABLE_SPS_LEAF_DATA
|
|
|
|
# define ENABLE_ARM_LR_SAVING
|
|
|
|
# endif
|
|
|
|
# define LOG(text) \
|
|
|
|
__android_log_write(ANDROID_LOG_ERROR, "Profiler", text)
|
|
|
|
# define LOGF(format, ...) \
|
|
|
|
__android_log_print(ANDROID_LOG_ERROR, "Profiler", format, __VA_ARGS__)
|
|
|
|
|
2013-03-14 11:37:04 -07:00
|
|
|
#else
|
2013-04-06 01:45:30 -07:00
|
|
|
extern bool moz_profiler_verbose();
|
|
|
|
# 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)
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
#endif
|
|
|
|
|
2012-05-04 12:33:35 -07:00
|
|
|
#if defined(XP_MACOSX) || defined(XP_WIN)
|
2012-05-03 18:23:27 -07:00
|
|
|
#define ENABLE_SPS_LEAF_DATA
|
|
|
|
#endif
|
|
|
|
|
2011-12-23 04:21:35 -08:00
|
|
|
typedef uint8_t* Address;
|
2011-08-26 17:05:37 -07:00
|
|
|
|
2011-12-01 07:06:20 -08:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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;
|
|
|
|
};
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ScopedLock
|
|
|
|
//
|
|
|
|
// Stack-allocated ScopedLocks provide block-scoped locking and
|
|
|
|
// unlocking of a mutex.
|
|
|
|
class ScopedLock {
|
|
|
|
public:
|
|
|
|
explicit ScopedLock(Mutex* mutex): mutex_(mutex) {
|
|
|
|
ASSERT(mutex_ != NULL);
|
|
|
|
mutex_->Lock();
|
|
|
|
}
|
|
|
|
~ScopedLock() {
|
|
|
|
mutex_->Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Mutex* mutex_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ScopedLock);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Factory method for creating platform dependent Mutex.
|
|
|
|
// Please use delete to reclaim the storage for the returned Mutex.
|
|
|
|
static Mutex* CreateMutex();
|
|
|
|
|
2012-03-02 11:11:47 -08:00
|
|
|
// On supported platforms, setup a signal handler which would start
|
2012-07-11 07:55:22 -07:00
|
|
|
// the profiler.
|
|
|
|
#if defined(ANDROID)
|
|
|
|
static void RegisterStartHandler();
|
|
|
|
#else
|
|
|
|
static void RegisterStartHandler() {}
|
|
|
|
#endif
|
2012-03-02 11:11:47 -08:00
|
|
|
|
2011-12-01 07:06:20 -08:00
|
|
|
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();
|
|
|
|
|
2011-12-07 11:48:15 -08:00
|
|
|
void Join();
|
|
|
|
|
2011-12-01 07:06:20 -08:00
|
|
|
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;
|
|
|
|
|
2013-04-18 05:15:09 -07:00
|
|
|
class PlatformData;
|
|
|
|
PlatformData* data() { return data_; }
|
2011-12-01 07:06:20 -08:00
|
|
|
|
|
|
|
private:
|
|
|
|
void set_name(const char *name);
|
|
|
|
|
2013-04-18 05:15:09 -07:00
|
|
|
PlatformData* data_;
|
|
|
|
|
2011-12-01 07:06:20 -08:00
|
|
|
char name_[kMaxThreadNameLength];
|
|
|
|
int stack_size_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Thread);
|
|
|
|
};
|
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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) \
|
2013-04-02 08:39:04 -07:00
|
|
|
|| defined(SPS_PLAT_x86_linux) \
|
|
|
|
|| defined(SPS_OS_windows) \
|
|
|
|
|| defined(SPS_OS_darwin))
|
2013-03-25 14:57:28 -07:00
|
|
|
# define HAVE_NATIVE_UNWIND
|
|
|
|
#endif
|
2011-08-26 17:05:37 -07:00
|
|
|
|
2013-04-06 01:49:11 -07:00
|
|
|
/* Some values extracted at startup from environment variables, that
|
|
|
|
control the behaviour of the breakpad unwinder. */
|
|
|
|
void read_profiler_env_vars();
|
|
|
|
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 */
|
|
|
|
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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.
|
|
|
|
|
2013-03-29 12:34:49 -07:00
|
|
|
class PseudoStack;
|
|
|
|
class ThreadProfile;
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
// TickSample captures the information collected for each sample.
|
|
|
|
class TickSample {
|
|
|
|
public:
|
|
|
|
TickSample()
|
|
|
|
:
|
|
|
|
pc(NULL),
|
|
|
|
sp(NULL),
|
|
|
|
fp(NULL),
|
2012-07-04 08:25:15 -07:00
|
|
|
#ifdef ENABLE_ARM_LR_SAVING
|
|
|
|
lr(NULL),
|
|
|
|
#endif
|
2011-08-26 17:05:37 -07:00
|
|
|
function(NULL),
|
2012-03-02 11:11:47 -08:00
|
|
|
context(NULL),
|
2011-08-26 17:05:37 -07:00
|
|
|
frames_count(0) {}
|
|
|
|
Address pc; // Instruction pointer.
|
|
|
|
Address sp; // Stack pointer.
|
|
|
|
Address fp; // Frame pointer.
|
2012-07-04 08:25:15 -07:00
|
|
|
#ifdef ENABLE_ARM_LR_SAVING
|
|
|
|
Address lr; // ARM link register
|
|
|
|
#endif
|
2011-08-26 17:05:37 -07:00
|
|
|
Address function; // The last called JS function.
|
2012-12-07 21:15:21 -08:00
|
|
|
void* context; // The context from the signal handler, if available. On
|
|
|
|
// Win32 this may contain the windows thread context.
|
2013-03-29 12:34:49 -07:00
|
|
|
ThreadProfile* threadProfile;
|
2011-08-26 17:05:37 -07:00
|
|
|
static const int kMaxFramesCount = 64;
|
|
|
|
int frames_count; // Number of captured frames.
|
2011-12-24 09:11:26 -08:00
|
|
|
mozilla::TimeStamp timestamp;
|
2011-08-26 17:05:37 -07:00
|
|
|
};
|
|
|
|
|
2013-03-29 12:34:49 -07:00
|
|
|
class ThreadInfo {
|
|
|
|
public:
|
|
|
|
ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, PseudoStack* aPseudoStack)
|
|
|
|
: mName(strdup(aName))
|
|
|
|
, mThreadId(aThreadId)
|
|
|
|
, mIsMainThread(aIsMainThread)
|
|
|
|
, mPseudoStack(aPseudoStack)
|
|
|
|
, mProfile(NULL) {}
|
|
|
|
|
|
|
|
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; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
char* mName;
|
|
|
|
int mThreadId;
|
|
|
|
const bool mIsMainThread;
|
|
|
|
PseudoStack* mPseudoStack;
|
|
|
|
ThreadProfile* mProfile;
|
|
|
|
};
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
class Sampler {
|
|
|
|
public:
|
|
|
|
// Initialize sampler.
|
2013-03-29 12:34:49 -07:00
|
|
|
explicit Sampler(int interval, bool profiling, int entrySize);
|
2011-08-26 17:05:37 -07:00
|
|
|
virtual ~Sampler();
|
|
|
|
|
2011-12-01 07:06:20 -08:00
|
|
|
int interval() const { return interval_; }
|
|
|
|
|
2013-04-18 05:15:09 -07:00
|
|
|
// Performs stack sampling.
|
|
|
|
virtual void SampleStack(TickSample* sample) = 0;
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
// This method is called for each sampling period with the current
|
|
|
|
// program counter.
|
|
|
|
virtual void Tick(TickSample* sample) = 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_; }
|
|
|
|
|
2012-05-18 14:03:10 -07:00
|
|
|
// Low overhead way to stop the sampler from ticking
|
|
|
|
bool IsPaused() const { return paused_; }
|
|
|
|
void SetPaused(bool value) { NoBarrier_Store(&paused_, value); }
|
|
|
|
|
2013-03-29 12:34:49 -07:00
|
|
|
int EntrySize() { return entrySize_; }
|
|
|
|
|
2013-04-18 05:15:09 -07:00
|
|
|
class PlatformData;
|
2011-08-26 17:05:37 -07:00
|
|
|
|
2013-04-18 05:15:09 -07:00
|
|
|
PlatformData* platform_data() { return data_; }
|
2011-12-01 07:06:20 -08:00
|
|
|
|
2012-02-14 21:17:34 -08:00
|
|
|
// If we move the backtracing code into the platform files we won't
|
|
|
|
// need to have these hacks
|
2012-01-16 16:59:15 -08:00
|
|
|
#ifdef XP_WIN
|
|
|
|
// xxxehsan sucky hack :(
|
|
|
|
static uintptr_t GetThreadHandle(PlatformData*);
|
|
|
|
#endif
|
2012-02-14 21:17:34 -08:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
static pthread_t GetProfiledThread(PlatformData*);
|
|
|
|
#endif
|
2013-03-29 12:34:49 -07:00
|
|
|
|
|
|
|
static std::vector<ThreadInfo*> GetRegisteredThreads() {
|
|
|
|
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
|
|
|
|
|
|
|
return *sRegisteredThreads;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread);
|
|
|
|
static void UnregisterCurrentThread();
|
|
|
|
|
|
|
|
// Should only be called on shutdown
|
|
|
|
static void FreeRegisteredThreads() {
|
|
|
|
while (sRegisteredThreads->size() > 0) {
|
|
|
|
sRegisteredThreads->pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
delete sRegisteredThreadsMutex;
|
|
|
|
delete sRegisteredThreads;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Sampler* GetActiveSampler() { return sActiveSampler; }
|
|
|
|
static void SetActiveSampler(Sampler* sampler) { sActiveSampler = sampler; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
static std::vector<ThreadInfo*>* sRegisteredThreads;
|
|
|
|
static mozilla::Mutex* sRegisteredThreadsMutex;
|
|
|
|
static Sampler* sActiveSampler;
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
private:
|
2011-10-31 10:25:04 -07:00
|
|
|
void SetActive(bool value) { NoBarrier_Store(&active_, value); }
|
|
|
|
|
2011-08-26 17:05:37 -07:00
|
|
|
const int interval_;
|
|
|
|
const bool profiling_;
|
2012-05-18 14:03:10 -07:00
|
|
|
Atomic32 paused_;
|
2011-10-31 10:25:04 -07:00
|
|
|
Atomic32 active_;
|
2013-03-29 12:34:49 -07:00
|
|
|
const int entrySize_;
|
2013-04-18 05:15:09 -07:00
|
|
|
PlatformData* data_; // Platform specific data.
|
2011-08-26 17:05:37 -07:00
|
|
|
};
|
|
|
|
|
2013-03-10 15:00:23 -07:00
|
|
|
#endif /* ndef TOOLS_PLATFORM_H_ */
|