mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out changesets ab64b048ad04 and 025d24d7fee8 (bug 734691) for leaks.
This commit is contained in:
parent
a17a62df52
commit
8a408a9bc9
@ -42,8 +42,6 @@
|
||||
#include "OSFileConstants.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -265,10 +263,6 @@ JSBool
|
||||
OperationCallback(JSContext* aCx)
|
||||
{
|
||||
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||
|
||||
// Now is a good time to turn on profiling if it's pending.
|
||||
profiler_js_operation_callback();
|
||||
|
||||
return worker->OperationCallback(aCx);
|
||||
}
|
||||
|
||||
@ -521,19 +515,13 @@ public:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
|
||||
profiler_register_thread("WebWorker");
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
if (PseudoStack* stack = mozilla_get_pseudo_stack())
|
||||
stack->sampleRuntime(rt);
|
||||
#endif
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
workerPrivate->DoRunLoop(cx);
|
||||
}
|
||||
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
|
||||
// XXX Bug 666963 - CTypes can create another JSContext for use with
|
||||
// closures, and then it holds that context in a reserved slot on the CType
|
||||
// prototype object. We have to destroy that context before we can destroy
|
||||
@ -552,14 +540,9 @@ public:
|
||||
JS_DestroyContext(cx);
|
||||
}
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
if (PseudoStack* stack = mozilla_get_pseudo_stack())
|
||||
stack->sampleRuntime(nullptr);
|
||||
#endif
|
||||
JS_DestroyRuntime(rt);
|
||||
|
||||
workerPrivate->ScheduleDeletion(false);
|
||||
profiler_unregister_thread();
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "base/string_util.h"
|
||||
#include "base/thread_local.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -137,8 +136,6 @@ void Thread::StopSoon() {
|
||||
}
|
||||
|
||||
void Thread::ThreadMain() {
|
||||
profiler_register_thread(name_.c_str());
|
||||
|
||||
// The message loop for this thread.
|
||||
MessageLoop message_loop(startup_data_->options.message_loop_type);
|
||||
|
||||
@ -164,8 +161,6 @@ void Thread::ThreadMain() {
|
||||
// Assert that MessageLoop::Quit was called by ThreadQuitTask.
|
||||
DCHECK(GetThreadWasQuitProperly());
|
||||
|
||||
profiler_unregister_thread();
|
||||
|
||||
// We can't receive messages anymore.
|
||||
message_loop_ = NULL;
|
||||
thread_id_ = 0;
|
||||
|
@ -158,13 +158,6 @@ void genPseudoBacktraceEntries(/*MODIFIED*/UnwinderThreadBuffer* utb,
|
||||
// RUNS IN SIGHANDLER CONTEXT
|
||||
void BreakpadSampler::Tick(TickSample* sample)
|
||||
{
|
||||
if (!sample->threadProfile) {
|
||||
// Platform doesn't support multithread, so use the main thread profile we created
|
||||
sample->threadProfile = GetPrimaryThreadProfile();
|
||||
}
|
||||
|
||||
ThreadProfile& currThreadProfile = *sample->threadProfile;
|
||||
|
||||
/* Get hold of an empty inter-thread buffer into which to park
|
||||
the ProfileEntries for this sample. */
|
||||
UnwinderThreadBuffer* utb = uwt__acquire_empty_buffer();
|
||||
@ -179,7 +172,7 @@ void BreakpadSampler::Tick(TickSample* sample)
|
||||
thread, and park them in |utb|. */
|
||||
|
||||
// Marker(s) come before the sample
|
||||
PseudoStack* stack = currThreadProfile.GetPseudoStack();
|
||||
PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
|
||||
for (int i = 0; stack->getMarker(i) != NULL; i++) {
|
||||
utb__addEntry( utb, ProfileEntry('m', stack->getMarker(i)) );
|
||||
}
|
||||
@ -193,7 +186,7 @@ void BreakpadSampler::Tick(TickSample* sample)
|
||||
// XXX: we also probably want to add an entry to the profile to help
|
||||
// distinguish which samples are part of the same event. That, or record
|
||||
// the event generation in each sample
|
||||
currThreadProfile.erase();
|
||||
mPrimaryThreadProfile.erase();
|
||||
}
|
||||
sLastSampledEventGeneration = sCurrentEventGeneration;
|
||||
|
||||
@ -300,9 +293,9 @@ void BreakpadSampler::Tick(TickSample* sample)
|
||||
# else
|
||||
# error "Unsupported platform"
|
||||
# endif
|
||||
uwt__release_full_buffer(&currThreadProfile, utb, ucV);
|
||||
uwt__release_full_buffer(&mPrimaryThreadProfile, utb, ucV);
|
||||
} else {
|
||||
uwt__release_full_buffer(&currThreadProfile, utb, NULL);
|
||||
uwt__release_full_buffer(&mPrimaryThreadProfile, utb, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,13 +135,6 @@ static inline void profiler_lock() {}
|
||||
// Re-enable the profiler and notify 'profiler-unlocked'.
|
||||
static inline void profiler_unlock() {}
|
||||
|
||||
static inline void profiler_register_thread(const char* name) {}
|
||||
static inline void profiler_unregister_thread() {}
|
||||
|
||||
// Call by the JSRuntime's operation callback. This is used to enable
|
||||
// profiling on auxilerary threads.
|
||||
static inline void profiler_js_operation_callback() {}
|
||||
|
||||
#else
|
||||
|
||||
#include "GeckoProfilerImpl.h"
|
||||
|
@ -57,10 +57,6 @@ void mozilla_sampler_lock();
|
||||
// Unlock the profiler, leaving it stopped and fires profiler-unlocked.
|
||||
void mozilla_sampler_unlock();
|
||||
|
||||
// Register/unregister threads with the profiler
|
||||
bool mozilla_sampler_register_thread(const char* name);
|
||||
void mozilla_sampler_unregister_thread();
|
||||
|
||||
/* Returns true if env var SPS_NEW is set to anything, else false. */
|
||||
extern bool sps_version2();
|
||||
|
||||
|
@ -140,29 +140,6 @@ void profiler_unlock()
|
||||
return mozilla_sampler_unlock();
|
||||
}
|
||||
|
||||
static inline
|
||||
void profiler_register_thread(const char* name)
|
||||
{
|
||||
mozilla_sampler_register_thread(name);
|
||||
}
|
||||
|
||||
static inline
|
||||
void profiler_unregister_thread()
|
||||
{
|
||||
mozilla_sampler_unregister_thread();
|
||||
}
|
||||
|
||||
static inline
|
||||
void profiler_js_operation_callback()
|
||||
{
|
||||
PseudoStack *stack = tlsPseudoStack.get();
|
||||
if (!stack) {
|
||||
return;
|
||||
}
|
||||
|
||||
stack->jsOperationCallback();
|
||||
}
|
||||
|
||||
// we want the class and function name but can't easily get that using preprocessor macros
|
||||
// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
|
||||
|
||||
@ -177,7 +154,6 @@ void profiler_js_operation_callback()
|
||||
#define PROFILER_MAIN_THREAD_LABEL_PRINTF(name_space, info, ...) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, __LINE__, __VA_ARGS__)
|
||||
#define PROFILER_MAIN_THREAD_MARKER(info) MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread"); mozilla_sampler_add_marker(info)
|
||||
|
||||
|
||||
/* FIXME/bug 789667: memory constraints wouldn't much of a problem for
|
||||
* this small a sample buffer size, except that serializing the
|
||||
* profile data is extremely, unnecessarily memory intensive. */
|
||||
|
@ -43,9 +43,6 @@ ifndef _MSC_VER
|
||||
FAIL_ON_WARNINGS = 1
|
||||
endif # !_MSC_VER
|
||||
|
||||
# Uncomment for better debugging in opt builds
|
||||
#MOZ_OPTIMIZE_FLAGS += -O0 -g
|
||||
|
||||
CPPSRCS = \
|
||||
platform.cpp \
|
||||
nsProfilerFactory.cpp \
|
||||
|
@ -134,27 +134,19 @@ std::ostream& operator<<(std::ostream& stream, const ProfileEntry& entry)
|
||||
|
||||
#define DYNAMIC_MAX_STRING 512
|
||||
|
||||
ThreadProfile::ThreadProfile(const char* aName, int aEntrySize,
|
||||
PseudoStack *aStack, int aThreadId,
|
||||
PlatformData* aPlatform,
|
||||
bool aIsMainThread)
|
||||
ThreadProfile::ThreadProfile(int aEntrySize, PseudoStack *aStack)
|
||||
: mWritePos(0)
|
||||
, mLastFlushPos(0)
|
||||
, mReadPos(0)
|
||||
, mEntrySize(aEntrySize)
|
||||
, mPseudoStack(aStack)
|
||||
, mMutex("ThreadProfile::mMutex")
|
||||
, mName(strdup(aName))
|
||||
, mThreadId(aThreadId)
|
||||
, mIsMainThread(aIsMainThread)
|
||||
, mPlatformData(aPlatform)
|
||||
{
|
||||
mEntries = new ProfileEntry[mEntrySize];
|
||||
}
|
||||
|
||||
ThreadProfile::~ThreadProfile()
|
||||
{
|
||||
free(mName);
|
||||
delete[] mEntries;
|
||||
}
|
||||
|
||||
@ -307,10 +299,6 @@ JSCustomObject* ThreadProfile::ToJSObject(JSContext *aCx)
|
||||
}
|
||||
|
||||
void ThreadProfile::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile) {
|
||||
// Thread meta data
|
||||
b.DefineProperty(profile, "name", mName);
|
||||
b.DefineProperty(profile, "tid", mThreadId);
|
||||
|
||||
JSCustomArray *samples = b.CreateArray();
|
||||
b.DefineProperty(profile, "samples", samples);
|
||||
|
||||
|
@ -6,12 +6,12 @@
|
||||
#ifndef MOZ_PROFILE_ENTRY_H
|
||||
#define MOZ_PROFILE_ENTRY_H
|
||||
|
||||
#include <ostream>
|
||||
#include "GeckoProfilerImpl.h"
|
||||
#include "JSAObjectBuilder.h"
|
||||
#include "platform.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
class ThreadProfile;
|
||||
class ThreadProfile;
|
||||
|
||||
class ProfileEntry
|
||||
@ -56,9 +56,7 @@ typedef void (*IterateTagsCallback)(const ProfileEntry& entry, const char* tagSt
|
||||
class ThreadProfile
|
||||
{
|
||||
public:
|
||||
ThreadProfile(const char* aName, int aEntrySize, PseudoStack *aStack,
|
||||
int aThreadId, PlatformData* aPlatformData,
|
||||
bool aIsMainThread);
|
||||
ThreadProfile(int aEntrySize, PseudoStack *aStack);
|
||||
~ThreadProfile();
|
||||
void addTag(ProfileEntry aTag);
|
||||
void flush();
|
||||
@ -72,12 +70,6 @@ public:
|
||||
PseudoStack* GetPseudoStack();
|
||||
mozilla::Mutex* GetMutex();
|
||||
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
|
||||
|
||||
bool IsMainThread() const { return mIsMainThread; }
|
||||
const char* Name() const { return mName; }
|
||||
int ThreadId() const { return mThreadId; }
|
||||
|
||||
PlatformData* GetPlatformData() { return mPlatformData; }
|
||||
private:
|
||||
// Circular buffer 'Keep One Slot Open' implementation
|
||||
// for simplicity
|
||||
@ -88,10 +80,6 @@ private:
|
||||
int mEntrySize;
|
||||
PseudoStack* mPseudoStack;
|
||||
mozilla::Mutex mMutex;
|
||||
char* mName;
|
||||
int mThreadId;
|
||||
bool mIsMainThread;
|
||||
PlatformData* mPlatformData; // Platform specific data.
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const ThreadProfile& profile);
|
||||
|
@ -220,10 +220,6 @@ public:
|
||||
mStartJSSampling = true;
|
||||
}
|
||||
}
|
||||
void jsOperationCallback() {
|
||||
if (mStartJSSampling)
|
||||
enableJSSampling();
|
||||
}
|
||||
void disableJSSampling() {
|
||||
mStartJSSampling = false;
|
||||
if (mRuntime)
|
||||
|
@ -173,26 +173,16 @@ void TableTicker::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile)
|
||||
JSCustomArray *threads = b.CreateArray();
|
||||
b.DefineProperty(profile, "threads", threads);
|
||||
|
||||
// For now we only have one thread
|
||||
SetPaused(true);
|
||||
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
// Thread not being profiled, skip it
|
||||
if (!sRegisteredThreads->at(i)->Profile())
|
||||
continue;
|
||||
|
||||
MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
|
||||
|
||||
JSCustomObject* threadSamples = b.CreateObject();
|
||||
sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples);
|
||||
b.ArrayPush(threads, threadSamples);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadProfile* prof = GetPrimaryThreadProfile();
|
||||
prof->GetMutex()->Lock();
|
||||
JSCustomObject* threadSamples = b.CreateObject();
|
||||
prof->BuildJSObject(b, threadSamples);
|
||||
b.ArrayPush(threads, threadSamples);
|
||||
prof->GetMutex()->Unlock();
|
||||
SetPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
// END SaveProfileTask et al
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@ -295,7 +285,7 @@ void StackWalkCallback(void* aPC, void* aSP, void* aClosure)
|
||||
void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
|
||||
{
|
||||
#ifndef XP_MACOSX
|
||||
uintptr_t thread = GetThreadHandle(aSample->threadProfile->GetPlatformData());
|
||||
uintptr_t thread = GetThreadHandle(platform_data());
|
||||
MOZ_ASSERT(thread);
|
||||
#endif
|
||||
void* pc_array[1000];
|
||||
@ -312,7 +302,7 @@ void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample
|
||||
|
||||
uint32_t maxFrames = uint32_t(array.size - array.count);
|
||||
#ifdef XP_MACOSX
|
||||
pthread_t pt = GetProfiledThread(aSample->threadProfile->GetPlatformData());
|
||||
pthread_t pt = GetProfiledThread(platform_data());
|
||||
void *stackEnd = reinterpret_cast<void*>(-1);
|
||||
if (pt)
|
||||
stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
|
||||
@ -393,12 +383,10 @@ void doSampleStackTrace(PseudoStack *aStack, ThreadProfile &aProfile, TickSample
|
||||
|
||||
void TableTicker::Tick(TickSample* sample)
|
||||
{
|
||||
ThreadProfile& currThreadProfile = *sample->threadProfile;
|
||||
|
||||
// Marker(s) come before the sample
|
||||
PseudoStack* stack = currThreadProfile.GetPseudoStack();
|
||||
PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
|
||||
for (int i = 0; stack->getMarker(i) != NULL; i++) {
|
||||
addDynamicTag(currThreadProfile, 'm', stack->getMarker(i));
|
||||
addDynamicTag(mPrimaryThreadProfile, 'm', stack->getMarker(i));
|
||||
}
|
||||
stack->mQueueClearMarker = true;
|
||||
|
||||
@ -410,7 +398,7 @@ void TableTicker::Tick(TickSample* sample)
|
||||
// XXX: we also probably want to add an entry to the profile to help
|
||||
// distinguish which samples are part of the same event. That, or record
|
||||
// the event generation in each sample
|
||||
currThreadProfile.erase();
|
||||
mPrimaryThreadProfile.erase();
|
||||
}
|
||||
sLastSampledEventGeneration = sCurrentEventGeneration;
|
||||
|
||||
@ -426,29 +414,29 @@ void TableTicker::Tick(TickSample* sample)
|
||||
|
||||
#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
|
||||
if (mUseStackWalk) {
|
||||
doNativeBacktrace(currThreadProfile, sample);
|
||||
doNativeBacktrace(mPrimaryThreadProfile, sample);
|
||||
} else {
|
||||
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
|
||||
doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
|
||||
}
|
||||
#else
|
||||
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
|
||||
doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
|
||||
#endif
|
||||
|
||||
if (recordSample)
|
||||
currThreadProfile.flush();
|
||||
mPrimaryThreadProfile.flush();
|
||||
|
||||
if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
|
||||
if (!sLastTracerEvent.IsNull() && sample) {
|
||||
TimeDuration delta = sample->timestamp - sLastTracerEvent;
|
||||
currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
|
||||
mPrimaryThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
|
||||
}
|
||||
|
||||
if (sample) {
|
||||
TimeDuration delta = sample->timestamp - mStartTime;
|
||||
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
|
||||
mPrimaryThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
|
||||
}
|
||||
|
||||
if (sLastFrameNumber != sFrameNumber) {
|
||||
currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
|
||||
mPrimaryThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
|
||||
sLastFrameNumber = sFrameNumber;
|
||||
}
|
||||
}
|
||||
@ -472,8 +460,7 @@ void mozilla_sampler_print_location1()
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadProfile threadProfile("Temp", PROFILE_DEFAULT_ENTRY, stack,
|
||||
0, Sampler::AllocPlatformData(0), false);
|
||||
ThreadProfile threadProfile(1000, stack);
|
||||
doSampleStackTrace(stack, threadProfile, NULL);
|
||||
|
||||
threadProfile.flush();
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "platform.h"
|
||||
#include "ProfileEntry.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
static bool
|
||||
hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) {
|
||||
@ -26,10 +25,10 @@ class BreakpadSampler;
|
||||
|
||||
class TableTicker: public Sampler {
|
||||
public:
|
||||
TableTicker(int aInterval, int aEntrySize,
|
||||
TableTicker(int aInterval, int aEntrySize, PseudoStack *aStack,
|
||||
const char** aFeatures, uint32_t aFeatureCount)
|
||||
: Sampler(aInterval, true, aEntrySize)
|
||||
, mPrimaryThreadProfile(nullptr)
|
||||
: Sampler(aInterval, true)
|
||||
, mPrimaryThreadProfile(aEntrySize, aStack)
|
||||
, mStartTime(TimeStamp::Now())
|
||||
, mSaveRequested(false)
|
||||
{
|
||||
@ -38,54 +37,13 @@ class TableTicker: public Sampler {
|
||||
//XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point
|
||||
mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
|
||||
mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
|
||||
mProfileThreads = true || hasFeature(aFeatures, aFeatureCount, "threads");
|
||||
mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
|
||||
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
// Create ThreadProfile for each registered thread
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
|
||||
if (!info->IsMainThread() && !mProfileThreads)
|
||||
continue;
|
||||
|
||||
ThreadProfile* profile = new ThreadProfile(info->Name(),
|
||||
aEntrySize,
|
||||
info->Stack(),
|
||||
info->ThreadId(),
|
||||
info->GetPlatformData(),
|
||||
info->IsMainThread());
|
||||
profile->addTag(ProfileEntry('m', "Start"));
|
||||
|
||||
info->SetProfile(profile);
|
||||
}
|
||||
|
||||
SetActiveSampler(this);
|
||||
}
|
||||
mPrimaryThreadProfile.addTag(ProfileEntry('m', "Start"));
|
||||
}
|
||||
|
||||
~TableTicker() {
|
||||
if (IsActive())
|
||||
Stop();
|
||||
~TableTicker() { if (IsActive()) Stop(); }
|
||||
|
||||
SetActiveSampler(nullptr);
|
||||
|
||||
// Destroy ThreadProfile for all threads
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
ThreadProfile* profile = info->Profile();
|
||||
if (profile) {
|
||||
delete profile;
|
||||
info->SetProfile(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void SampleStack(TickSample* sample) {}
|
||||
|
||||
// Called within a signal. This function must be reentrant
|
||||
virtual void Tick(TickSample* sample);
|
||||
@ -100,27 +58,14 @@ class TableTicker: public Sampler {
|
||||
|
||||
ThreadProfile* GetPrimaryThreadProfile()
|
||||
{
|
||||
if (!mPrimaryThreadProfile) {
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
if (info->IsMainThread()) {
|
||||
mPrimaryThreadProfile = info->Profile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mPrimaryThreadProfile;
|
||||
return &mPrimaryThreadProfile;
|
||||
}
|
||||
|
||||
void ToStreamAsJSON(std::ostream& stream);
|
||||
virtual JSObject *ToJSObject(JSContext *aCx);
|
||||
JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
|
||||
|
||||
bool ProfileJS() const { return mProfileJS; }
|
||||
bool ProfileThreads() const { return mProfileThreads; }
|
||||
const bool ProfileJS() { return mProfileJS; }
|
||||
|
||||
virtual BreakpadSampler* AsBreakpadSampler() { return nullptr; }
|
||||
|
||||
@ -131,21 +76,20 @@ protected:
|
||||
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
|
||||
|
||||
// This represent the application's main thread (SAMPLER_INIT)
|
||||
ThreadProfile* mPrimaryThreadProfile;
|
||||
ThreadProfile mPrimaryThreadProfile;
|
||||
TimeStamp mStartTime;
|
||||
bool mSaveRequested;
|
||||
bool mAddLeafAddresses;
|
||||
bool mUseStackWalk;
|
||||
bool mJankOnly;
|
||||
bool mProfileJS;
|
||||
bool mProfileThreads;
|
||||
};
|
||||
|
||||
class BreakpadSampler: public TableTicker {
|
||||
public:
|
||||
BreakpadSampler(int aInterval, int aEntrySize,
|
||||
BreakpadSampler(int aInterval, int aEntrySize, PseudoStack *aStack,
|
||||
const char** aFeatures, uint32_t aFeatureCount)
|
||||
: TableTicker(aInterval, aEntrySize, aFeatures, aFeatureCount)
|
||||
: TableTicker(aInterval, aEntrySize, aStack, aFeatures, aFeatureCount)
|
||||
{}
|
||||
|
||||
// Called within a signal. This function must be reentrant
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#else
|
||||
@ -61,14 +60,9 @@
|
||||
#include <stdarg.h>
|
||||
#include "platform.h"
|
||||
#include "GeckoProfilerImpl.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "ProfileEntry.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "TableTicker.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
|
||||
#define SIGNAL_SAVE_PROFILE SIGUSR2
|
||||
|
||||
@ -81,27 +75,15 @@ pid_t gettid()
|
||||
}
|
||||
#endif
|
||||
|
||||
static Sampler* sActiveSampler = NULL;
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "android-signal-defs.h"
|
||||
#endif
|
||||
|
||||
struct SamplerRegistry {
|
||||
static void AddActiveSampler(Sampler *sampler) {
|
||||
ASSERT(!SamplerRegistry::sampler);
|
||||
SamplerRegistry::sampler = sampler;
|
||||
}
|
||||
static void RemoveActiveSampler(Sampler *sampler) {
|
||||
SamplerRegistry::sampler = NULL;
|
||||
}
|
||||
static Sampler *sampler;
|
||||
};
|
||||
|
||||
Sampler *SamplerRegistry::sampler = NULL;
|
||||
|
||||
static ThreadProfile* sCurrentThreadProfile = NULL;
|
||||
|
||||
static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
Sampler::GetActiveSampler()->RequestSave();
|
||||
sActiveSampler->RequestSave();
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -112,7 +94,7 @@ static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context
|
||||
#define V8_HOST_ARCH_X64 1
|
||||
#endif
|
||||
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
if (!Sampler::GetActiveSampler())
|
||||
if (!sActiveSampler)
|
||||
return;
|
||||
|
||||
TickSample sample_obj;
|
||||
@ -121,7 +103,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
|
||||
#ifdef ENABLE_SPS_LEAF_DATA
|
||||
// If profiling, we extract the current pc and sp.
|
||||
if (Sampler::GetActiveSampler()->IsProfiling()) {
|
||||
if (sActiveSampler->IsProfiling()) {
|
||||
// Extracting the sample from the context is extremely machine dependent.
|
||||
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
||||
mcontext_t& mcontext = ucontext->uc_mcontext;
|
||||
@ -156,103 +138,94 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
sample->threadProfile = sCurrentThreadProfile;
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
|
||||
Sampler::GetActiveSampler()->Tick(sample);
|
||||
|
||||
sCurrentThreadProfile = NULL;
|
||||
sActiveSampler->Tick(sample);
|
||||
}
|
||||
|
||||
int tgkill(pid_t tgid, pid_t tid, int signalno) {
|
||||
return syscall(SYS_tgkill, tgid, tid, signalno);
|
||||
#ifndef XP_MACOSX
|
||||
void tgkill(pid_t tgid, pid_t tid, int signalno) {
|
||||
syscall(SYS_tgkill, tgid, tid, signalno);
|
||||
}
|
||||
#endif
|
||||
|
||||
class PlatformData : public Malloced {
|
||||
class Sampler::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData()
|
||||
explicit PlatformData(Sampler* sampler)
|
||||
: sampler_(sampler),
|
||||
signal_handler_installed_(false),
|
||||
vm_tgid_(getpid()),
|
||||
#ifndef XP_MACOSX
|
||||
vm_tid_(gettid()),
|
||||
#endif
|
||||
signal_sender_launched_(false)
|
||||
#ifdef XP_MACOSX
|
||||
, signal_receiver_(pthread_self())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
void SignalSender() {
|
||||
while (sampler_->IsActive()) {
|
||||
sampler_->HandleSaveRequest();
|
||||
|
||||
if (!sampler_->IsPaused()) {
|
||||
#ifdef XP_MACOSX
|
||||
pthread_kill(signal_receiver_, SIGPROF);
|
||||
#else
|
||||
// Glibc doesn't provide a wrapper for tgkill(2).
|
||||
tgkill(vm_tgid_, vm_tid_, SIGPROF);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert ms to us and subtract 100 us to compensate delays
|
||||
// occuring during signal delivery.
|
||||
// TODO measure and confirm this.
|
||||
const useconds_t interval = sampler_->interval_ * 1000 - 100;
|
||||
//int result = usleep(interval);
|
||||
usleep(interval);
|
||||
}
|
||||
}
|
||||
|
||||
Sampler* sampler_;
|
||||
bool signal_handler_installed_;
|
||||
struct sigaction old_sigprof_signal_handler_;
|
||||
struct sigaction old_sigsave_signal_handler_;
|
||||
pid_t vm_tgid_;
|
||||
pid_t vm_tid_;
|
||||
bool signal_sender_launched_;
|
||||
pthread_t signal_sender_thread_;
|
||||
#ifdef XP_MACOSX
|
||||
pthread_t signal_receiver_;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* static */ PlatformData*
|
||||
Sampler::AllocPlatformData(int aThreadId)
|
||||
{
|
||||
return new PlatformData;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Sampler::FreePlatformData(PlatformData* aData)
|
||||
{
|
||||
delete aData;
|
||||
}
|
||||
|
||||
static void* SignalSender(void* arg) {
|
||||
int vm_tgid_ = getpid();
|
||||
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
SamplerRegistry::sampler->HandleSaveRequest();
|
||||
|
||||
if (!SamplerRegistry::sampler->IsPaused()) {
|
||||
std::vector<ThreadInfo*> threads =
|
||||
SamplerRegistry::sampler->GetRegisteredThreads();
|
||||
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->Profile())
|
||||
continue;
|
||||
|
||||
// We use sCurrentThreadProfile the ThreadProfile for the
|
||||
// thread we're profiling to the signal handler
|
||||
sCurrentThreadProfile = info->Profile();
|
||||
|
||||
int threadId = info->ThreadId();
|
||||
|
||||
if (tgkill(vm_tgid_, threadId, SIGPROF) != 0) {
|
||||
printf_stderr("profiler failed to signal tid=%d\n", threadId);
|
||||
#ifdef DEBUG
|
||||
abort();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for the signal handler to run before moving on to the next one
|
||||
while (sCurrentThreadProfile)
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
// Convert ms to us and subtract 100 us to compensate delays
|
||||
// occuring during signal delivery.
|
||||
// TODO measure and confirm this.
|
||||
const useconds_t interval =
|
||||
SamplerRegistry::sampler->interval() * 1000 - 100;
|
||||
//int result = usleep(interval);
|
||||
usleep(interval);
|
||||
}
|
||||
static void* SenderEntry(void* arg) {
|
||||
Sampler::PlatformData* data =
|
||||
reinterpret_cast<Sampler::PlatformData*>(arg);
|
||||
data->SignalSender();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Sampler::Sampler(int interval, bool profiling, int entrySize)
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: interval_(interval),
|
||||
profiling_(profiling),
|
||||
paused_(false),
|
||||
active_(false),
|
||||
entrySize_(entrySize) {
|
||||
active_(false) {
|
||||
data_ = new PlatformData(this);
|
||||
}
|
||||
|
||||
Sampler::~Sampler() {
|
||||
ASSERT(!signal_sender_launched_);
|
||||
ASSERT(!data_->signal_sender_launched_);
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
void Sampler::Start() {
|
||||
LOG("Sampler started");
|
||||
|
||||
SamplerRegistry::AddActiveSampler(this);
|
||||
if (sActiveSampler != NULL) return;
|
||||
|
||||
// Request profiling signals.
|
||||
LOG("Request signal");
|
||||
@ -260,7 +233,7 @@ void Sampler::Start() {
|
||||
sa.sa_sigaction = ProfilerSignalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
if (sigaction(SIGPROF, &sa, &old_sigprof_signal_handler_) != 0) {
|
||||
if (sigaction(SIGPROF, &sa, &data_->old_sigprof_signal_handler_) != 0) {
|
||||
LOG("Error installing signal");
|
||||
return;
|
||||
}
|
||||
@ -270,22 +243,25 @@ void Sampler::Start() {
|
||||
sa2.sa_sigaction = ProfilerSaveSignalHandler;
|
||||
sigemptyset(&sa2.sa_mask);
|
||||
sa2.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &old_sigsave_signal_handler_) != 0) {
|
||||
if (sigaction(SIGNAL_SAVE_PROFILE, &sa2, &data_->old_sigsave_signal_handler_) != 0) {
|
||||
LOG("Error installing start signal");
|
||||
return;
|
||||
}
|
||||
LOG("Signal installed");
|
||||
signal_handler_installed_ = true;
|
||||
data_->signal_handler_installed_ = true;
|
||||
|
||||
// Start a thread that sends SIGPROF signal to VM thread.
|
||||
// Sending the signal ourselves instead of relying on itimer provides
|
||||
// much better accuracy.
|
||||
SetActive(true);
|
||||
if (pthread_create(
|
||||
&signal_sender_thread_, NULL, SignalSender, NULL) == 0) {
|
||||
signal_sender_launched_ = true;
|
||||
&data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
|
||||
data_->signal_sender_launched_ = true;
|
||||
}
|
||||
LOG("Profiler thread started");
|
||||
|
||||
// Set this sampler as the active sampler.
|
||||
sActiveSampler = this;
|
||||
}
|
||||
|
||||
|
||||
@ -294,62 +270,20 @@ void Sampler::Stop() {
|
||||
|
||||
// Wait for signal sender termination (it will exit after setting
|
||||
// active_ to false).
|
||||
if (signal_sender_launched_) {
|
||||
pthread_join(signal_sender_thread_, NULL);
|
||||
signal_sender_launched_ = false;
|
||||
if (data_->signal_sender_launched_) {
|
||||
pthread_join(data_->signal_sender_thread_, NULL);
|
||||
data_->signal_sender_launched_ = false;
|
||||
}
|
||||
|
||||
SamplerRegistry::RemoveActiveSampler(this);
|
||||
|
||||
// Restore old signal handler
|
||||
if (signal_handler_installed_) {
|
||||
sigaction(SIGNAL_SAVE_PROFILE, &old_sigsave_signal_handler_, 0);
|
||||
sigaction(SIGPROF, &old_sigprof_signal_handler_, 0);
|
||||
signal_handler_installed_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
ThreadInfo* info = new ThreadInfo(aName, gettid(),
|
||||
aIsMainThread, aPseudoStack);
|
||||
|
||||
bool profileThread = sActiveSampler &&
|
||||
(aIsMainThread || sActiveSampler->ProfileThreads());
|
||||
|
||||
if (profileThread) {
|
||||
// We need to create the ThreadProfile now
|
||||
info->SetProfile(new ThreadProfile(info->Name(),
|
||||
sActiveSampler->EntrySize(),
|
||||
info->Stack(),
|
||||
info->ThreadId(),
|
||||
info->GetPlatformData(),
|
||||
aIsMainThread));
|
||||
if (sActiveSampler->ProfileJS()) {
|
||||
info->Profile()->GetPseudoStack()->enableJSSampling();
|
||||
}
|
||||
if (data_->signal_handler_installed_) {
|
||||
sigaction(SIGNAL_SAVE_PROFILE, &data_->old_sigsave_signal_handler_, 0);
|
||||
sigaction(SIGPROF, &data_->old_sigprof_signal_handler_, 0);
|
||||
data_->signal_handler_installed_ = false;
|
||||
}
|
||||
|
||||
sRegisteredThreads->push_back(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sampler::UnregisterCurrentThread()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
int id = gettid();
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
if (info->ThreadId() == id) {
|
||||
delete info;
|
||||
sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// This sampler is no longer the active sampler.
|
||||
sActiveSampler = NULL;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -373,4 +307,3 @@ void OS::RegisterStartHandler()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -28,10 +28,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "platform.h"
|
||||
#include "TableTicker.h"
|
||||
#include "UnwinderThread2.h" /* uwt__register_thread_for_profiling */
|
||||
|
||||
// this port is based off of v8 svn revision 9837
|
||||
@ -92,13 +89,21 @@ void OS::Sleep(int milliseconds) {
|
||||
usleep(1000 * milliseconds);
|
||||
}
|
||||
|
||||
class Thread::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData() : thread_(kNoThread) {}
|
||||
pthread_t thread_; // Thread handle for pthread.
|
||||
};
|
||||
|
||||
Thread::Thread(const char* name)
|
||||
: stack_size_(0) {
|
||||
: data_(new PlatformData),
|
||||
stack_size_(0) {
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread() {
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
@ -134,9 +139,9 @@ static void* ThreadEntry(void* arg) {
|
||||
}
|
||||
// END temp hack for SPS v1-vs-v2
|
||||
|
||||
thread->thread_ = pthread_self();
|
||||
thread->data()->thread_ = pthread_self();
|
||||
SetThreadName(thread->name());
|
||||
ASSERT(thread->thread_ != kNoThread);
|
||||
ASSERT(thread->data()->thread_ != kNoThread);
|
||||
thread->Run();
|
||||
return NULL;
|
||||
}
|
||||
@ -156,15 +161,15 @@ void Thread::Start() {
|
||||
pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
|
||||
attr_ptr = &attr;
|
||||
}
|
||||
pthread_create(&thread_, attr_ptr, ThreadEntry, this);
|
||||
ASSERT(thread_ != kNoThread);
|
||||
pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
|
||||
ASSERT(data_->thread_ != kNoThread);
|
||||
}
|
||||
|
||||
void Thread::Join() {
|
||||
pthread_join(thread_, NULL);
|
||||
pthread_join(data_->thread_, NULL);
|
||||
}
|
||||
|
||||
class PlatformData : public Malloced {
|
||||
class Sampler::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData() : profiled_thread_(mach_thread_self())
|
||||
{
|
||||
@ -190,23 +195,12 @@ class PlatformData : public Malloced {
|
||||
pthread_t profiled_pthread_;
|
||||
};
|
||||
|
||||
/* static */ PlatformData*
|
||||
Sampler::AllocPlatformData(int aThreadId)
|
||||
{
|
||||
return new PlatformData;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Sampler::FreePlatformData(PlatformData* aData)
|
||||
{
|
||||
delete aData;
|
||||
}
|
||||
|
||||
class SamplerThread : public Thread {
|
||||
public:
|
||||
explicit SamplerThread(int interval)
|
||||
: Thread("SamplerThread")
|
||||
, interval_(interval) {}
|
||||
: Thread("SamplerThread"),
|
||||
interval_(interval) {}
|
||||
|
||||
static void AddActiveSampler(Sampler* sampler) {
|
||||
ScopedLock lock(mutex_);
|
||||
@ -227,35 +221,30 @@ class SamplerThread : public Thread {
|
||||
SamplerRegistry::RemoveActiveSampler(sampler);
|
||||
delete instance_;
|
||||
instance_ = NULL;
|
||||
/*
|
||||
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
|
||||
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
|
||||
delete instance_;
|
||||
instance_ = NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Implement Thread::Run().
|
||||
virtual void Run() {
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
std::vector<ThreadInfo*> threads =
|
||||
SamplerRegistry::sampler->GetRegisteredThreads();
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->Profile())
|
||||
continue;
|
||||
|
||||
ThreadProfile* thread_profile = info->Profile();
|
||||
|
||||
if (!SamplerRegistry::sampler->IsPaused())
|
||||
SampleContext(SamplerRegistry::sampler, thread_profile);
|
||||
}
|
||||
if (!SamplerRegistry::sampler->IsPaused())
|
||||
SampleContext(SamplerRegistry::sampler);
|
||||
OS::Sleep(interval_);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
|
||||
thread_act_t profiled_thread =
|
||||
thread_profile->GetPlatformData()->profiled_thread();
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
//TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
|
||||
//if (sample == NULL) sample = &sample_obj;
|
||||
|
||||
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
|
||||
|
||||
@ -285,11 +274,12 @@ class SamplerThread : public Thread {
|
||||
flavor,
|
||||
reinterpret_cast<natural_t*>(&state),
|
||||
&count) == KERN_SUCCESS) {
|
||||
//sample->state = sampler->isolate()->current_vm_state();
|
||||
sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
|
||||
sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
|
||||
sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->threadProfile = thread_profile;
|
||||
sampler->SampleStack(sample);
|
||||
sampler->Tick(sample);
|
||||
}
|
||||
thread_resume(profiled_thread);
|
||||
@ -312,19 +302,20 @@ Mutex* SamplerThread::mutex_ = OS::CreateMutex();
|
||||
SamplerThread* SamplerThread::instance_ = NULL;
|
||||
|
||||
|
||||
Sampler::Sampler(int interval, bool profiling, int entrySize)
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: // isolate_(isolate),
|
||||
interval_(interval),
|
||||
profiling_(profiling),
|
||||
paused_(false),
|
||||
active_(false),
|
||||
entrySize_(entrySize) /*,
|
||||
active_(false) /*,
|
||||
samples_taken_(0)*/ {
|
||||
data_ = new PlatformData;
|
||||
}
|
||||
|
||||
|
||||
Sampler::~Sampler() {
|
||||
ASSERT(!IsActive());
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
@ -342,56 +333,7 @@ void Sampler::Stop() {
|
||||
}
|
||||
|
||||
pthread_t
|
||||
Sampler::GetProfiledThread(PlatformData* aData)
|
||||
Sampler::GetProfiledThread(Sampler::PlatformData* aData)
|
||||
{
|
||||
return aData->profiled_pthread();
|
||||
}
|
||||
|
||||
#include <sys/syscall.h>
|
||||
pid_t gettid()
|
||||
{
|
||||
return (pid_t) syscall(SYS_thread_selfid);
|
||||
}
|
||||
|
||||
bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
ThreadInfo* info = new ThreadInfo(aName, gettid(),
|
||||
aIsMainThread, aPseudoStack);
|
||||
|
||||
bool profileThread = sActiveSampler &&
|
||||
(aIsMainThread || sActiveSampler->ProfileThreads());
|
||||
|
||||
if (profileThread) {
|
||||
// We need to create the ThreadProfile now
|
||||
info->SetProfile(new ThreadProfile(info->Name(),
|
||||
sActiveSampler->EntrySize(),
|
||||
info->Stack(),
|
||||
info->ThreadId(),
|
||||
info->GetPlatformData(),
|
||||
aIsMainThread));
|
||||
if (sActiveSampler->ProfileJS()) {
|
||||
info->Profile()->GetPseudoStack()->enableJSSampling();
|
||||
}
|
||||
}
|
||||
|
||||
sRegisteredThreads->push_back(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sampler::UnregisterCurrentThread()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
int id = gettid();
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
if (info->ThreadId() == id) {
|
||||
delete info;
|
||||
sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,23 +28,22 @@
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <process.h>
|
||||
#include "platform.h"
|
||||
#include "TableTicker.h"
|
||||
#include "ProfileEntry.h"
|
||||
#include <process.h>
|
||||
|
||||
class PlatformData : public Malloced {
|
||||
|
||||
class Sampler::PlatformData : public Malloced {
|
||||
public:
|
||||
// Get a handle to the calling thread. This is the thread that we are
|
||||
// going to profile. We need to make a copy of the handle because we are
|
||||
// going to use it in the sampler thread. Using GetThreadHandle() will
|
||||
// not work in this case. We're using OpenThread because DuplicateHandle
|
||||
// for some reason doesn't work in Chrome's sandbox.
|
||||
PlatformData(int aThreadId) : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
|
||||
PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
|
||||
THREAD_SUSPEND_RESUME |
|
||||
THREAD_QUERY_INFORMATION,
|
||||
false,
|
||||
aThreadId)) {}
|
||||
GetCurrentThreadId())) {}
|
||||
|
||||
~PlatformData() {
|
||||
if (profiled_thread_ != NULL) {
|
||||
@ -59,20 +58,8 @@ class PlatformData : public Malloced {
|
||||
HANDLE profiled_thread_;
|
||||
};
|
||||
|
||||
/* static */ PlatformData*
|
||||
Sampler::AllocPlatformData(int aThreadId)
|
||||
{
|
||||
return new PlatformData(aThreadId);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Sampler::FreePlatformData(PlatformData* aData)
|
||||
{
|
||||
delete aData;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
Sampler::GetThreadHandle(PlatformData* aData)
|
||||
Sampler::GetThreadHandle(Sampler::PlatformData* aData)
|
||||
{
|
||||
return (uintptr_t) aData->profiled_thread();
|
||||
}
|
||||
@ -80,9 +67,9 @@ Sampler::GetThreadHandle(PlatformData* aData)
|
||||
class SamplerThread : public Thread {
|
||||
public:
|
||||
SamplerThread(int interval, Sampler* sampler)
|
||||
: Thread("SamplerThread")
|
||||
, interval_(interval)
|
||||
, sampler_(sampler) {}
|
||||
: Thread("SamplerThread"),
|
||||
interval_(interval),
|
||||
sampler_(sampler) {}
|
||||
|
||||
static void StartSampler(Sampler* sampler) {
|
||||
if (instance_ == NULL) {
|
||||
@ -109,21 +96,8 @@ class SamplerThread : public Thread {
|
||||
::timeBeginPeriod(interval_);
|
||||
|
||||
while (sampler_->IsActive()) {
|
||||
std::vector<ThreadInfo*> threads =
|
||||
sampler_->GetRegisteredThreads();
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
|
||||
// This will be null if we're not interested in profiling this thread.
|
||||
if (!info->Profile())
|
||||
continue;
|
||||
|
||||
ThreadProfile* thread_profile = info->Profile();
|
||||
|
||||
if (!sampler_->IsPaused()) {
|
||||
SampleContext(sampler_, thread_profile);
|
||||
}
|
||||
}
|
||||
if (!sampler_->IsPaused())
|
||||
SampleContext(sampler_);
|
||||
OS::Sleep(interval_);
|
||||
}
|
||||
|
||||
@ -132,10 +106,8 @@ class SamplerThread : public Thread {
|
||||
::timeEndPeriod(interval_);
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
|
||||
uintptr_t thread = Sampler::GetThreadHandle(
|
||||
thread_profile->GetPlatformData());
|
||||
HANDLE profiled_thread = reinterpret_cast<HANDLE>(thread);
|
||||
void SampleContext(Sampler* sampler) {
|
||||
HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
if (profiled_thread == NULL)
|
||||
return;
|
||||
|
||||
@ -148,7 +120,6 @@ class SamplerThread : public Thread {
|
||||
|
||||
// Grab the timestamp before pausing the thread, to avoid deadlocks.
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->threadProfile = thread_profile;
|
||||
|
||||
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
|
||||
if (SuspendThread(profiled_thread) == kSuspendFailed)
|
||||
@ -166,6 +137,7 @@ class SamplerThread : public Thread {
|
||||
sample->fp = reinterpret_cast<Address>(context.Ebp);
|
||||
#endif
|
||||
sample->context = &context;
|
||||
sampler->SampleStack(sample);
|
||||
sampler->Tick(sample);
|
||||
}
|
||||
ResumeThread(profiled_thread);
|
||||
@ -183,16 +155,17 @@ class SamplerThread : public Thread {
|
||||
SamplerThread* SamplerThread::instance_ = NULL;
|
||||
|
||||
|
||||
Sampler::Sampler(int interval, bool profiling, int entrySize)
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: interval_(interval),
|
||||
profiling_(profiling),
|
||||
paused_(false),
|
||||
active_(false),
|
||||
entrySize_(entrySize) {
|
||||
data_(new PlatformData) {
|
||||
}
|
||||
|
||||
Sampler::~Sampler() {
|
||||
ASSERT(!IsActive());
|
||||
delete data_;
|
||||
}
|
||||
|
||||
void Sampler::Start() {
|
||||
@ -216,11 +189,18 @@ static unsigned int __stdcall ThreadEntry(void* arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Thread::PlatformData : public Malloced {
|
||||
public:
|
||||
explicit PlatformData(HANDLE thread) : thread_(thread) {}
|
||||
HANDLE thread_;
|
||||
unsigned thread_id_;
|
||||
};
|
||||
|
||||
// Initialize a Win32 thread object. The thread has an invalid thread
|
||||
// handle until it is started.
|
||||
Thread::Thread(const char* name)
|
||||
: stack_size_(0) {
|
||||
thread_ = kNoThread;
|
||||
data_ = new PlatformData(kNoThread);
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
@ -231,72 +211,30 @@ void Thread::set_name(const char* name) {
|
||||
|
||||
// Close our own handle for the thread.
|
||||
Thread::~Thread() {
|
||||
if (thread_ != kNoThread) CloseHandle(thread_);
|
||||
if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
|
||||
delete data_;
|
||||
}
|
||||
|
||||
// Create a new thread. It is important to use _beginthreadex() instead of
|
||||
// the Win32 function CreateThread(), because the CreateThread() does not
|
||||
// initialize thread specific structures in the C runtime library.
|
||||
void Thread::Start() {
|
||||
thread_ = reinterpret_cast<HANDLE>(
|
||||
data_->thread_ = reinterpret_cast<HANDLE>(
|
||||
_beginthreadex(NULL,
|
||||
static_cast<unsigned>(stack_size_),
|
||||
ThreadEntry,
|
||||
this,
|
||||
0,
|
||||
&thread_id_));
|
||||
&data_->thread_id_));
|
||||
}
|
||||
|
||||
// Wait for thread to terminate.
|
||||
void Thread::Join() {
|
||||
if (thread_id_ != GetCurrentThreadId()) {
|
||||
WaitForSingleObject(thread_, INFINITE);
|
||||
if (data_->thread_id_ != GetCurrentThreadId()) {
|
||||
WaitForSingleObject(data_->thread_, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
void OS::Sleep(int milliseconds) {
|
||||
::Sleep(milliseconds);
|
||||
}
|
||||
|
||||
bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread)
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
ThreadInfo* info = new ThreadInfo(aName, GetCurrentThreadId(),
|
||||
aIsMainThread, aPseudoStack);
|
||||
|
||||
bool profileThread = sActiveSampler &&
|
||||
(aIsMainThread || sActiveSampler->ProfileThreads());
|
||||
|
||||
if (profileThread) {
|
||||
// We need to create the ThreadProfile now
|
||||
info->SetProfile(new ThreadProfile(info->Name(),
|
||||
sActiveSampler->EntrySize(),
|
||||
info->Stack(),
|
||||
GetCurrentThreadId(),
|
||||
info->GetPlatformData(),
|
||||
aIsMainThread));
|
||||
if (sActiveSampler->ProfileJS()) {
|
||||
info->Profile()->GetPseudoStack()->enableJSSampling();
|
||||
}
|
||||
}
|
||||
|
||||
sRegisteredThreads->push_back(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sampler::UnregisterCurrentThread()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
int id = GetCurrentThreadId();
|
||||
|
||||
for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
|
||||
ThreadInfo* info = sRegisteredThreads->at(i);
|
||||
if (info->ThreadId() == id) {
|
||||
delete info;
|
||||
sRegisteredThreads->erase(sRegisteredThreads->begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
|
||||
mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
||||
@ -28,16 +27,15 @@ mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
||||
// it as the flag itself.
|
||||
bool stack_key_initialized;
|
||||
|
||||
TimeStamp sLastTracerEvent; // is raced on
|
||||
int sFrameNumber = 0;
|
||||
int sLastFrameNumber = 0;
|
||||
static bool sIsProfiling = false; // is raced on
|
||||
TimeStamp sLastTracerEvent; // is raced on
|
||||
int sFrameNumber = 0;
|
||||
int sLastFrameNumber = 0;
|
||||
|
||||
/* used to keep track of the last event that we sampled during */
|
||||
unsigned int sLastSampledEventGeneration = 0;
|
||||
|
||||
/* a counter that's incremented everytime we get responsiveness event
|
||||
* note: it might also be worth trackplaing everytime we go around
|
||||
* note: it might also be worth tracking everytime we go around
|
||||
* the event loop */
|
||||
unsigned int sCurrentEventGeneration = 0;
|
||||
/* we don't need to worry about overflow because we only treat the
|
||||
@ -45,20 +43,6 @@ unsigned int sCurrentEventGeneration = 0;
|
||||
* a problem if 2^32 events happen between samples that we need
|
||||
* to know are associated with different events */
|
||||
|
||||
std::vector<ThreadInfo*>* Sampler::sRegisteredThreads = nullptr;
|
||||
mozilla::Mutex* Sampler::sRegisteredThreadsMutex = nullptr;
|
||||
|
||||
TableTicker* Sampler::sActiveSampler;
|
||||
|
||||
ThreadInfo::~ThreadInfo() {
|
||||
free(mName);
|
||||
|
||||
if (mProfile)
|
||||
delete mProfile;
|
||||
|
||||
Sampler::FreePlatformData(mPlatformData);
|
||||
}
|
||||
|
||||
bool sps_version2()
|
||||
{
|
||||
static int version = 0; // Raced on, potentially
|
||||
@ -238,13 +222,9 @@ void mozilla_sampler_init()
|
||||
}
|
||||
stack_key_initialized = true;
|
||||
|
||||
Sampler::Startup();
|
||||
|
||||
PseudoStack *stack = new PseudoStack();
|
||||
tlsPseudoStack.set(stack);
|
||||
|
||||
Sampler::RegisterCurrentThread("Gecko", stack, true);
|
||||
|
||||
if (sps_version2()) {
|
||||
// Read mode settings from MOZ_PROFILER_MODE and interval
|
||||
// settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
|
||||
@ -314,9 +294,6 @@ void mozilla_sampler_shutdown()
|
||||
}
|
||||
|
||||
profiler_stop();
|
||||
|
||||
Sampler::Shutdown();
|
||||
|
||||
// We can't delete the Stack because we can be between a
|
||||
// sampler call_enter/call_exit point.
|
||||
// TODO Need to find a safe time to delete Stack
|
||||
@ -375,7 +352,6 @@ const char** mozilla_sampler_get_features()
|
||||
#endif
|
||||
"jank",
|
||||
"js",
|
||||
"threads",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -407,28 +383,16 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval,
|
||||
if (sps_version2()) {
|
||||
t = new BreakpadSampler(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
|
||||
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
|
||||
aFeatures, aFeatureCount);
|
||||
stack, aFeatures, aFeatureCount);
|
||||
} else {
|
||||
t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
|
||||
aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
|
||||
aFeatures, aFeatureCount);
|
||||
stack, aFeatures, aFeatureCount);
|
||||
}
|
||||
tlsTicker.set(t);
|
||||
t->Start();
|
||||
if (t->ProfileJS()) {
|
||||
std::vector<ThreadInfo*> threads = t->GetRegisteredThreads();
|
||||
|
||||
for (uint32_t i = 0; i < threads.size(); i++) {
|
||||
ThreadInfo* info = threads[i];
|
||||
ThreadProfile* thread_profile = info->Profile();
|
||||
if (!thread_profile) {
|
||||
continue;
|
||||
}
|
||||
thread_profile->GetPseudoStack()->enableJSSampling();
|
||||
}
|
||||
}
|
||||
|
||||
sIsProfiling = true;
|
||||
if (t->ProfileJS())
|
||||
stack->enableJSSampling();
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os)
|
||||
@ -456,8 +420,6 @@ void mozilla_sampler_stop()
|
||||
if (disableJS)
|
||||
stack->disableJSSampling();
|
||||
|
||||
sIsProfiling = false;
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
if (os)
|
||||
os->NotifyObservers(nullptr, "profiler-stopped", nullptr);
|
||||
@ -465,7 +427,15 @@ void mozilla_sampler_stop()
|
||||
|
||||
bool mozilla_sampler_is_active()
|
||||
{
|
||||
return sIsProfiling;
|
||||
if (!stack_key_initialized)
|
||||
profiler_init();
|
||||
|
||||
TableTicker *t = tlsTicker.get();
|
||||
if (!t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return t->IsActive();
|
||||
}
|
||||
|
||||
static double sResponsivenessTimes[100];
|
||||
@ -517,20 +487,6 @@ void mozilla_sampler_unlock()
|
||||
os->NotifyObservers(nullptr, "profiler-unlocked", nullptr);
|
||||
}
|
||||
|
||||
bool mozilla_sampler_register_thread(const char* aName)
|
||||
{
|
||||
PseudoStack* stack = new PseudoStack();
|
||||
tlsPseudoStack.set(stack);
|
||||
|
||||
return Sampler::RegisterCurrentThread(aName, stack, false);
|
||||
}
|
||||
|
||||
void mozilla_sampler_unregister_thread()
|
||||
{
|
||||
Sampler::UnregisterCurrentThread();
|
||||
}
|
||||
|
||||
// END externally visible functions
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
@ -35,23 +35,14 @@
|
||||
#define __android_log_print(a, ...)
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/StandardInteger.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "PlatformMacros.h"
|
||||
#include "v8-support.h"
|
||||
#include <vector>
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define ASSERT(a) MOZ_ASSERT(a)
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -192,17 +183,14 @@ class Thread {
|
||||
// prctl().
|
||||
static const int kMaxThreadNameLength = 16;
|
||||
|
||||
#ifdef XP_WIN
|
||||
HANDLE thread_;
|
||||
unsigned thread_id_;
|
||||
#endif
|
||||
#if defined(XP_MACOSX)
|
||||
pthread_t thread_;
|
||||
#endif
|
||||
class PlatformData;
|
||||
PlatformData* data() { return data_; }
|
||||
|
||||
private:
|
||||
void set_name(const char *name);
|
||||
|
||||
PlatformData* data_;
|
||||
|
||||
char name_[kMaxThreadNameLength];
|
||||
int stack_size_;
|
||||
|
||||
@ -244,9 +232,6 @@ extern int sUnwindStackScan; /* max # of dubious frames allowed */
|
||||
// (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:
|
||||
@ -270,23 +255,23 @@ class TickSample {
|
||||
Address function; // The last called JS function.
|
||||
void* context; // The context from the signal handler, if available. On
|
||||
// Win32 this may contain the windows thread context.
|
||||
ThreadProfile* threadProfile;
|
||||
static const int kMaxFramesCount = 64;
|
||||
Address stack[kMaxFramesCount]; // Call stack.
|
||||
int frames_count; // Number of captured frames.
|
||||
mozilla::TimeStamp timestamp;
|
||||
};
|
||||
|
||||
class ThreadInfo;
|
||||
class PlatformData;
|
||||
class TableTicker;
|
||||
class Sampler {
|
||||
public:
|
||||
// Initialize sampler.
|
||||
explicit Sampler(int interval, bool profiling, int entrySize);
|
||||
explicit Sampler(int interval, bool profiling);
|
||||
virtual ~Sampler();
|
||||
|
||||
int interval() const { return interval_; }
|
||||
|
||||
// Performs stack sampling.
|
||||
virtual void SampleStack(TickSample* sample) = 0;
|
||||
|
||||
// This method is called for each sampling period with the current
|
||||
// program counter.
|
||||
virtual void Tick(TickSample* sample) = 0;
|
||||
@ -310,14 +295,9 @@ class Sampler {
|
||||
bool IsPaused() const { return paused_; }
|
||||
void SetPaused(bool value) { NoBarrier_Store(&paused_, value); }
|
||||
|
||||
virtual bool ProfileThreads() const = 0;
|
||||
class PlatformData;
|
||||
|
||||
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*);
|
||||
PlatformData* platform_data() { return data_; }
|
||||
|
||||
// If we move the backtracing code into the platform files we won't
|
||||
// need to have these hacks
|
||||
@ -328,39 +308,6 @@ class Sampler {
|
||||
#ifdef XP_MACOSX
|
||||
static pthread_t GetProfiledThread(PlatformData*);
|
||||
#endif
|
||||
|
||||
static std::vector<ThreadInfo*> GetRegisteredThreads() {
|
||||
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
|
||||
|
||||
return *sRegisteredThreads;
|
||||
}
|
||||
|
||||
static bool RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread);
|
||||
static void UnregisterCurrentThread();
|
||||
|
||||
static void Startup() {
|
||||
sRegisteredThreads = new std::vector<ThreadInfo*>();
|
||||
sRegisteredThreadsMutex = new mozilla::Mutex("sRegisteredThreads mutex");
|
||||
}
|
||||
|
||||
// Should only be called on shutdown
|
||||
static void Shutdown() {
|
||||
while (sRegisteredThreads->size() > 0) {
|
||||
sRegisteredThreads->pop_back();
|
||||
}
|
||||
|
||||
delete sRegisteredThreadsMutex;
|
||||
delete sRegisteredThreads;
|
||||
}
|
||||
|
||||
static TableTicker* GetActiveSampler() { return sActiveSampler; }
|
||||
static void SetActiveSampler(TableTicker* sampler) { sActiveSampler = sampler; }
|
||||
|
||||
protected:
|
||||
static std::vector<ThreadInfo*>* sRegisteredThreads;
|
||||
static mozilla::Mutex* sRegisteredThreadsMutex;
|
||||
static TableTicker* sActiveSampler;
|
||||
|
||||
private:
|
||||
void SetActive(bool value) { NoBarrier_Store(&active_, value); }
|
||||
|
||||
@ -368,47 +315,7 @@ class Sampler {
|
||||
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)
|
||||
: mName(strdup(aName))
|
||||
, mThreadId(aThreadId)
|
||||
, mIsMainThread(aIsMainThread)
|
||||
, mPseudoStack(aPseudoStack)
|
||||
, mPlatformData(Sampler::AllocPlatformData(aThreadId))
|
||||
, 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; }
|
||||
|
||||
PlatformData* GetPlatformData() const { return mPlatformData; }
|
||||
private:
|
||||
char* mName;
|
||||
int mThreadId;
|
||||
const bool mIsMainThread;
|
||||
PseudoStack* mPseudoStack;
|
||||
PlatformData* mPlatformData;
|
||||
ThreadProfile* mProfile;
|
||||
PlatformData* data_; // Platform specific data.
|
||||
};
|
||||
|
||||
#endif /* ndef TOOLS_PLATFORM_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user