Skip to content

Commit

Permalink
Backed out 4 changesets (bug 1357829) for build bustage in xpcshell\s…
Browse files Browse the repository at this point in the history
…elftest.py on windows 8 x64 opt. a=backout

Backed out changeset 8ea202bb1103 (bug 1357829)
Backed out changeset cebe4d7abeda (bug 1357829)
Backed out changeset 378d473c9619 (bug 1357829)
Backed out changeset 86ebe868d443 (bug 1357829)
  • Loading branch information
IrisHsiao committed May 19, 2017
1 parent 4604c92 commit 02cae69
Show file tree
Hide file tree
Showing 10 changed files with 578 additions and 492 deletions.
17 changes: 10 additions & 7 deletions toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,16 @@ function run_test() {
notEqual(endHangs.hangs[0].stack.length, 0);
equal(typeof endHangs.hangs[0].stack[0], "string");

// Make sure one of the hangs is a permanent
// hang containing a native stack.
ok(endHangs.hangs.some((hang) => (
hang.nativeStack &&
Array.isArray(hang.nativeStack.memoryMap) &&
Array.isArray(hang.nativeStack.stacks)
)));
// Native stack gathering is only enabled on Windows x86.
if (mozinfo.os == "win" && mozinfo.bits == 32) {
// Make sure one of the hangs is a permanent
// hang containing a native stack.
ok(endHangs.hangs.some((hang) => (
hang.nativeStack &&
Array.isArray(hang.nativeStack.memoryMap) &&
Array.isArray(hang.nativeStack.stacks)
)));
}

check_histogram(endHangs.hangs[0].histogram);

Expand Down
1 change: 0 additions & 1 deletion toolkit/components/telemetry/tests/unit/xpcshell.ini
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ tags = addons
tags = addons
[test_TelemetrySession_activeTicks.js]
[test_ThreadHangStats.js]
skip-if = os == "android" || os == "linux" # BHR is disabled on linux (bug 1365309)
run-sequentially = Bug 1046307, test can fail intermittently when CPU load is high
[test_TelemetrySend.js]
[test_ChildHistograms.js]
Expand Down
167 changes: 72 additions & 95 deletions tools/profiler/core/platform-linux-android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class PlatformData
};

////////////////////////////////////////////////////////////////////////
// BEGIN Sampler target specifics
// BEGIN SamplerThread target specifics

// The only way to reliably interrupt a Linux thread and inspect its register
// and stack state is by sending a signal to it, and doing the work inside the
Expand Down Expand Up @@ -199,7 +199,7 @@ struct SigHandlerCoordinator
ucontext_t mUContext; // Context at signal
};

struct SigHandlerCoordinator* Sampler::sSigHandlerCoordinator = nullptr;
struct SigHandlerCoordinator* SamplerThread::sSigHandlerCoordinator = nullptr;

static void
SigprofHandler(int aSignal, siginfo_t* aInfo, void* aContext)
Expand All @@ -208,26 +208,26 @@ SigprofHandler(int aSignal, siginfo_t* aInfo, void* aContext)
int savedErrno = errno;

MOZ_ASSERT(aSignal == SIGPROF);
MOZ_ASSERT(Sampler::sSigHandlerCoordinator);
MOZ_ASSERT(SamplerThread::sSigHandlerCoordinator);

// By sending us this signal, the sampler thread has sent us message 1 in
// the comment above, with the meaning "|sSigHandlerCoordinator| is ready
// for use, please copy your register context into it."
Sampler::sSigHandlerCoordinator->mUContext =
SamplerThread::sSigHandlerCoordinator->mUContext =
*static_cast<ucontext_t*>(aContext);

// Send message 2: tell the sampler thread that the context has been copied
// into |sSigHandlerCoordinator->mUContext|. sem_post can never fail by
// being interrupted by a signal, so there's no loop around this call.
int r = sem_post(&Sampler::sSigHandlerCoordinator->mMessage2);
int r = sem_post(&SamplerThread::sSigHandlerCoordinator->mMessage2);
MOZ_ASSERT(r == 0);

// At this point, the sampler thread assumes we are suspended, so we must
// not touch any global state here.

// Wait for message 3: the sampler thread tells us to resume.
while (true) {
r = sem_wait(&Sampler::sSigHandlerCoordinator->mMessage3);
r = sem_wait(&SamplerThread::sSigHandlerCoordinator->mMessage3);
if (r == -1 && errno == EINTR) {
// Interrupted by a signal. Try again.
continue;
Expand All @@ -240,19 +240,33 @@ SigprofHandler(int aSignal, siginfo_t* aInfo, void* aContext)
// Send message 4: tell the sampler thread that we are finished accessing
// |sSigHandlerCoordinator|. After this point it is not safe to touch
// |sSigHandlerCoordinator|.
r = sem_post(&Sampler::sSigHandlerCoordinator->mMessage4);
r = sem_post(&SamplerThread::sSigHandlerCoordinator->mMessage4);
MOZ_ASSERT(r == 0);

errno = savedErrno;
}

Sampler::Sampler(PSLockRef aLock)
: mMyPid(getpid())
static void*
ThreadEntry(void* aArg)
{
auto thread = static_cast<SamplerThread*>(aArg);
thread->mSamplerTid = gettid();
thread->Run();
return nullptr;
}

SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
double aIntervalMilliseconds)
: mActivityGeneration(aActivityGeneration)
, mIntervalMicroseconds(
std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
, mMyPid(getpid())
// We don't know what the sampler thread's ID will be until it runs, so set
// mSamplerTid to a dummy value and fill it in for real in
// SuspendAndSampleAndResumeThread().
// mSamplerTid to a dummy value and fill it in for real in ThreadEntry().
, mSamplerTid(-1)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());

#if defined(USE_EHABI_STACKWALK)
mozilla::EHABIStackWalkInit();
#elif defined(USE_LUL_STACKWALK)
Expand Down Expand Up @@ -290,29 +304,66 @@ Sampler::Sampler(PSLockRef aLock)
}
}
#endif

// Start the sampling thread. It repeatedly sends a SIGPROF signal. Sending
// the signal ourselves instead of relying on itimer provides much better
// accuracy.
if (pthread_create(&mThread, nullptr, ThreadEntry, this) != 0) {
MOZ_CRASH("pthread_create failed");
}
}

SamplerThread::~SamplerThread()
{
pthread_join(mThread, nullptr);
}

void
Sampler::Disable(PSLockRef aLock)
SamplerThread::Stop(PSLockRef aLock)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());

// Restore old signal handler. This is global state so it's important that
// we do it now, while gPSMutex is locked.
// we do it now, while gPSMutex is locked. It's safe to do this now even
// though this SamplerThread is still alive, because the next time the main
// loop of Run() iterates it won't get past the mActivityGeneration check,
// and so won't send any signals.
sigaction(SIGPROF, &mOldSigprofHandler, 0);
}

template<typename Func>
void
Sampler::SuspendAndSampleAndResumeThread(PSLockRef aLock,
TickSample& aSample,
const Func& aDoSample)
SamplerThread::SleepMicro(uint32_t aMicroseconds)
{
if (aMicroseconds >= 1000000) {
// Use usleep for larger intervals, because the nanosleep
// code below only supports intervals < 1 second.
MOZ_ALWAYS_TRUE(!::usleep(aMicroseconds));
return;
}

struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = aMicroseconds * 1000UL;

int rv = ::nanosleep(&ts, &ts);

while (rv != 0 && errno == EINTR) {
// Keep waiting in case of interrupt.
// nanosleep puts the remaining time back into ts.
rv = ::nanosleep(&ts, &ts);
}

MOZ_ASSERT(!rv, "nanosleep call failed");
}

void
SamplerThread::SuspendAndSampleAndResumeThread(PSLockRef aLock,
TickSample& aSample)
{
// Only one sampler thread can be sampling at once. So we expect to have
// complete control over |sSigHandlerCoordinator|.
MOZ_ASSERT(!sSigHandlerCoordinator);

if (mSamplerTid == -1) {
mSamplerTid = gettid();
}
int sampleeTid = aSample.mThreadId;
MOZ_RELEASE_ASSERT(sampleeTid != mSamplerTid);

Expand Down Expand Up @@ -359,7 +410,7 @@ Sampler::SuspendAndSampleAndResumeThread(PSLockRef aLock,
// Extract the current PC and sp.
FillInSample(aSample, &sSigHandlerCoordinator->mUContext);

aDoSample();
Tick(aLock, ActivePS::Buffer(aLock), aSample);

//----------------------------------------------------------------//
// Resume the target thread.
Expand Down Expand Up @@ -389,80 +440,6 @@ Sampler::SuspendAndSampleAndResumeThread(PSLockRef aLock,
sSigHandlerCoordinator = nullptr;
}

// END Sampler target specifics
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
// BEGIN SamplerThread target specifics

static void*
ThreadEntry(void* aArg)
{
auto thread = static_cast<SamplerThread*>(aArg);
thread->Run();
return nullptr;
}

SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
double aIntervalMilliseconds)
: Sampler(aLock)
, mActivityGeneration(aActivityGeneration)
, mIntervalMicroseconds(
std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());

// Start the sampling thread. It repeatedly sends a SIGPROF signal. Sending
// the signal ourselves instead of relying on itimer provides much better
// accuracy.
if (pthread_create(&mThread, nullptr, ThreadEntry, this) != 0) {
MOZ_CRASH("pthread_create failed");
}
}

SamplerThread::~SamplerThread()
{
pthread_join(mThread, nullptr);
}

void
SamplerThread::SleepMicro(uint32_t aMicroseconds)
{
if (aMicroseconds >= 1000000) {
// Use usleep for larger intervals, because the nanosleep
// code below only supports intervals < 1 second.
MOZ_ALWAYS_TRUE(!::usleep(aMicroseconds));
return;
}

struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = aMicroseconds * 1000UL;

int rv = ::nanosleep(&ts, &ts);

while (rv != 0 && errno == EINTR) {
// Keep waiting in case of interrupt.
// nanosleep puts the remaining time back into ts.
rv = ::nanosleep(&ts, &ts);
}

MOZ_ASSERT(!rv, "nanosleep call failed");
}

void
SamplerThread::Stop(PSLockRef aLock)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());

// Restore old signal handler. This is global state so it's important that
// we do it now, while gPSMutex is locked. It's safe to do this now even
// though this SamplerThread is still alive, because the next time the main
// loop of Run() iterates it won't get past the mActivityGeneration check,
// and so won't send any signals.
Sampler::Disable(aLock);
}

// END SamplerThread target specifics
////////////////////////////////////////////////////////////////////////

Expand Down
Loading

0 comments on commit 02cae69

Please sign in to comment.