Skip to content

Commit

Permalink
Bug 734691 - Add multi-thread support to profiler r=benwa
Browse files Browse the repository at this point in the history
--HG--
extra : rebase_source : b9ecaa62430dc4f04a2d00a742c4b2d30e479bb5
  • Loading branch information
snorp committed Mar 29, 2013
1 parent 3fa3e4a commit 4664b7f
Show file tree
Hide file tree
Showing 15 changed files with 400 additions and 68 deletions.
5 changes: 5 additions & 0 deletions dom/workers/RuntimeService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
#include "OSFileConstants.h"
#include <algorithm>

#include "GeckoProfiler.h"

using namespace mozilla;
using namespace mozilla::dom;

Expand Down Expand Up @@ -515,6 +517,8 @@ class WorkerThreadRunnable : public nsRunnable
return NS_ERROR_FAILURE;
}

profiler_register_thread("WebWorker");

{
JSAutoRequest ar(cx);
workerPrivate->DoRunLoop(cx);
Expand Down Expand Up @@ -543,6 +547,7 @@ class WorkerThreadRunnable : public nsRunnable
JS_DestroyRuntime(rt);

workerPrivate->ScheduleDeletion(false);
profiler_unregister_thread();
return NS_OK;
}
};
Expand Down
5 changes: 5 additions & 0 deletions ipc/chromium/src/base/thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "base/string_util.h"
#include "base/thread_local.h"
#include "base/waitable_event.h"
#include "GeckoProfiler.h"

namespace base {

Expand Down Expand Up @@ -136,6 +137,8 @@ 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);

Expand All @@ -161,6 +164,8 @@ 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;
Expand Down
15 changes: 11 additions & 4 deletions tools/profiler/BreakpadSampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ 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();
Expand All @@ -172,7 +179,7 @@ void BreakpadSampler::Tick(TickSample* sample)
thread, and park them in |utb|. */

// Marker(s) come before the sample
PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
PseudoStack* stack = currThreadProfile.GetPseudoStack();
for (int i = 0; stack->getMarker(i) != NULL; i++) {
utb__addEntry( utb, ProfileEntry('m', stack->getMarker(i)) );
}
Expand All @@ -186,7 +193,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
mPrimaryThreadProfile.erase();
currThreadProfile.erase();
}
sLastSampledEventGeneration = sCurrentEventGeneration;

Expand Down Expand Up @@ -293,9 +300,9 @@ void BreakpadSampler::Tick(TickSample* sample)
# else
# error "Unsupported platform"
# endif
uwt__release_full_buffer(&mPrimaryThreadProfile, utb, ucV);
uwt__release_full_buffer(&currThreadProfile, utb, ucV);
} else {
uwt__release_full_buffer(&mPrimaryThreadProfile, utb, NULL);
uwt__release_full_buffer(&currThreadProfile, utb, NULL);
}
}

Expand Down
3 changes: 3 additions & 0 deletions tools/profiler/GeckoProfiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ 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() {}

#else

#include "GeckoProfilerImpl.h"
Expand Down
4 changes: 4 additions & 0 deletions tools/profiler/GeckoProfilerFunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ 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();

Expand Down
13 changes: 13 additions & 0 deletions tools/profiler/GeckoProfilerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ 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();
}

// 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

Expand All @@ -154,6 +166,7 @@ void profiler_unlock()
#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. */
Expand Down
10 changes: 9 additions & 1 deletion tools/profiler/ProfileEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,23 @@ std::ostream& operator<<(std::ostream& stream, const ProfileEntry& entry)

#define DYNAMIC_MAX_STRING 512

ThreadProfile::ThreadProfile(int aEntrySize, PseudoStack *aStack)
ThreadProfile::ThreadProfile(const char* aName, int aEntrySize, PseudoStack *aStack, int aThreadId, bool aIsMainThread)
: mWritePos(0)
, mLastFlushPos(0)
, mReadPos(0)
, mEntrySize(aEntrySize)
, mPseudoStack(aStack)
, mMutex("ThreadProfile::mMutex")
, mName(strdup(aName))
, mThreadId(aThreadId)
, mIsMainThread(aIsMainThread)
{
mEntries = new ProfileEntry[mEntrySize];
}

ThreadProfile::~ThreadProfile()
{
free(mName);
delete[] mEntries;
}

Expand Down Expand Up @@ -299,6 +303,10 @@ 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);

Expand Down
11 changes: 10 additions & 1 deletion tools/profiler/ProfileEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef MOZ_PROFILE_ENTRY_H
#define MOZ_PROFILE_ENTRY_H

#include <ostream>
#include "GeckoProfilerImpl.h"
#include "JSAObjectBuilder.h"
#include "platform.h"
Expand Down Expand Up @@ -56,7 +57,7 @@ typedef void (*IterateTagsCallback)(const ProfileEntry& entry, const char* tagSt
class ThreadProfile
{
public:
ThreadProfile(int aEntrySize, PseudoStack *aStack);
ThreadProfile(const char* aName, int aEntrySize, PseudoStack *aStack, int aThreadId, bool aIsMainThread);
~ThreadProfile();
void addTag(ProfileEntry aTag);
void flush();
Expand All @@ -70,6 +71,11 @@ class ThreadProfile
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; }

private:
// Circular buffer 'Keep One Slot Open' implementation
// for simplicity
Expand All @@ -80,6 +86,9 @@ class ThreadProfile
int mEntrySize;
PseudoStack* mPseudoStack;
mozilla::Mutex mMutex;
char* mName;
int mThreadId;
bool mIsMainThread;
};

std::ostream& operator<<(std::ostream& stream, const ThreadProfile& profile);
Expand Down
54 changes: 34 additions & 20 deletions tools/profiler/TableTicker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,22 @@ 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);
ThreadProfile* prof = GetPrimaryThreadProfile();
prof->GetMutex()->Lock();
JSCustomObject* threadSamples = b.CreateObject();
prof->BuildJSObject(b, threadSamples);
b.ArrayPush(threads, threadSamples);
prof->GetMutex()->Unlock();

{
mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);

for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());

JSCustomObject* threadSamples = b.CreateObject();
sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples);
b.ArrayPush(threads, threadSamples);
}
}

SetPaused(false);
}
}

// END SaveProfileTask et al
////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -383,10 +389,17 @@ void doSampleStackTrace(PseudoStack *aStack, ThreadProfile &aProfile, TickSample

void TableTicker::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;

// Marker(s) come before the sample
PseudoStack* stack = mPrimaryThreadProfile.GetPseudoStack();
PseudoStack* stack = currThreadProfile.GetPseudoStack();
for (int i = 0; stack->getMarker(i) != NULL; i++) {
addDynamicTag(mPrimaryThreadProfile, 'm', stack->getMarker(i));
addDynamicTag(currThreadProfile, 'm', stack->getMarker(i));
}
stack->mQueueClearMarker = true;

Expand All @@ -398,7 +411,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
mPrimaryThreadProfile.erase();
currThreadProfile.erase();
}
sLastSampledEventGeneration = sCurrentEventGeneration;

Expand All @@ -414,29 +427,29 @@ void TableTicker::Tick(TickSample* sample)

#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
if (mUseStackWalk) {
doNativeBacktrace(mPrimaryThreadProfile, sample);
doNativeBacktrace(currThreadProfile, sample);
} else {
doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
}
#else
doSampleStackTrace(stack, mPrimaryThreadProfile, mAddLeafAddresses ? sample : nullptr);
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
#endif

if (recordSample)
mPrimaryThreadProfile.flush();
currThreadProfile.flush();

if (!sLastTracerEvent.IsNull() && sample) {
if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
mPrimaryThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
}

if (sample) {
TimeDuration delta = sample->timestamp - mStartTime;
mPrimaryThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
}

if (sLastFrameNumber != sFrameNumber) {
mPrimaryThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
sLastFrameNumber = sFrameNumber;
}
}
Expand All @@ -460,7 +473,8 @@ void mozilla_sampler_print_location1()
return;
}

ThreadProfile threadProfile(1000, stack);
ThreadProfile threadProfile("Temp", PROFILE_DEFAULT_ENTRY, stack,
0, false);
doSampleStackTrace(stack, threadProfile, NULL);

threadProfile.flush();
Expand Down
Loading

0 comments on commit 4664b7f

Please sign in to comment.