本文整理汇总了C++中PseudoStack类的典型用法代码示例。如果您正苦于以下问题:C++ PseudoStack类的具体用法?C++ PseudoStack怎么用?C++ PseudoStack使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了PseudoStack类的10个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: mozilla_sampler_shutdown
void mozilla_sampler_shutdown()
{
sInitCount--;
if (sInitCount > 0)
return;
// Save the profile on shutdown if requested.
GeckoSampler *t = tlsTicker.get();
if (t) {
const char *val = getenv("MOZ_PROFILER_SHUTDOWN");
if (val) {
std::ofstream stream;
stream.open(val);
if (stream.is_open()) {
t->ToStreamAsJSON(stream);
stream.close();
}
}
}
profiler_stop();
#ifndef SPS_STANDALONE
set_stderr_callback(nullptr);
#endif
Sampler::Shutdown();
#ifdef SPS_STANDALONE
mozilla::TimeStamp::Shutdown();
#endif
PseudoStack *stack = tlsPseudoStack.get();
stack->deref();
tlsPseudoStack.set(nullptr);
#ifdef MOZ_TASK_TRACER
mozilla::tasktracer::ShutdownTaskTracer();
#endif
}
示例2: mergeNativeBacktrace
static void mergeNativeBacktrace(ThreadProfile &aProfile, const PCArray &array) {
aProfile.addTag(ProfileEntry('s', "(root)"));
PseudoStack* stack = aProfile.GetPseudoStack();
uint32_t pseudoStackPos = 0;
/* We have two stacks, the native C stack we extracted from unwinding,
* and the pseudostack we managed during execution. We want to consolidate
* the two in order. We do so by merging using the approximate stack address
* when each entry was push. When pushing JS entry we may not now the stack
* address in which case we have a NULL stack address in which case we assume
* that it follows immediatly the previous element.
*
* C Stack | Address -- Pseudo Stack | Address
* main() | 0x100 run_js() | 0x40
* start() | 0x80 jsCanvas() | NULL
* timer() | 0x50 drawLine() | NULL
* azure() | 0x10
*
* Merged: main(), start(), timer(), run_js(), jsCanvas(), drawLine(), azure()
*/
// i is the index in C stack starting at main and decreasing
// pseudoStackPos is the position in the Pseudo stack starting
// at the first frame (run_js in the example) and increasing.
for (size_t i = array.count; i > 0; --i) {
while (pseudoStackPos < stack->stackSize()) {
volatile StackEntry& entry = stack->mStack[pseudoStackPos];
if (entry.stackAddress() < array.sp_array[i-1] && entry.stackAddress())
break;
addProfileEntry(entry, aProfile, stack, array.array[0]);
pseudoStackPos++;
}
aProfile.addTag(ProfileEntry('l', (void*)array.array[i-1]));
}
}
示例3: mozilla_sampler_get_backtrace_noalloc
// Fill the output buffer with the following pattern:
// "Lable 1" "\0" "Label 2" "\0" ... "Label N" "\0" "\0"
// TODO: use the unwinder instead of pseudo stack.
void mozilla_sampler_get_backtrace_noalloc(char *output, size_t outputSize)
{
MOZ_ASSERT(outputSize >= 2);
char *bound = output + outputSize - 2;
output[0] = output[1] = '\0';
PseudoStack *pseudoStack = tlsPseudoStack.get();
if (!pseudoStack) {
return;
}
volatile StackEntry *pseudoFrames = pseudoStack->mStack;
uint32_t pseudoCount = pseudoStack->stackSize();
for (uint32_t i = 0; i < pseudoCount; i++) {
size_t len = strlen(pseudoFrames[i].label());
if (output + len >= bound)
break;
strcpy(output, pseudoFrames[i].label());
output += len;
*output++ = '\0';
*output = '\0';
}
}
示例4: InplaceTick
void TableTicker::InplaceTick(TickSample* sample)
{
ThreadProfile& currThreadProfile = *sample->threadProfile;
PseudoStack* stack = currThreadProfile.GetPseudoStack();
bool recordSample = true;
/* Don't process the PeudoStack's markers or honour jankOnly if we're
immediately sampling the current thread. */
if (!sample->isSamplingCurrentThread) {
// Marker(s) come before the sample
ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers();
while (pendingMarkersList && pendingMarkersList->peek()) {
ProfilerMarker* marker = pendingMarkersList->popHead();
stack->addStoredMarker(marker);
currThreadProfile.addTag(ProfileEntry('m', marker));
}
stack->updateGeneration(currThreadProfile.GetGenerationID());
if (mJankOnly) {
// if we are on a different event we can discard any temporary samples
// we've kept around
if (sLastSampledEventGeneration != sCurrentEventGeneration) {
// 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();
}
sLastSampledEventGeneration = sCurrentEventGeneration;
recordSample = false;
// only record the events when we have a we haven't seen a tracer event for 100ms
if (!sLastTracerEvent.IsNull()) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
if (delta.ToMilliseconds() > 100.0) {
recordSample = true;
}
}
}
}
#if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK)
if (mUseStackWalk) {
doNativeBacktrace(currThreadProfile, sample);
} else {
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
}
#else
doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
#endif
if (recordSample)
currThreadProfile.flush();
if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
}
if (sample) {
TimeDuration delta = sample->timestamp - sStartTime;
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
}
if (sLastFrameNumber != sFrameNumber) {
currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
sLastFrameNumber = sFrameNumber;
}
}
示例5: doNativeBacktrace
void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
{
void *pc_array[1000];
void *sp_array[1000];
PCArray array = {
pc_array,
sp_array,
mozilla::ArrayLength(pc_array),
0
};
const mcontext_t *mcontext = &reinterpret_cast<ucontext_t *>(aSample->context)->uc_mcontext;
mcontext_t savedContext;
PseudoStack *pseudoStack = aProfile.GetPseudoStack();
array.count = 0;
// The pseudostack contains an "EnterJIT" frame whenever we enter
// JIT code with profiling enabled; the stack pointer value points
// the saved registers. We use this to unwind resume unwinding
// after encounting JIT code.
for (uint32_t i = pseudoStack->stackSize(); i > 0; --i) {
// The pseudostack grows towards higher indices, so we iterate
// backwards (from callee to caller).
volatile StackEntry &entry = pseudoStack->mStack[i - 1];
if (!entry.js() && strcmp(entry.label(), "EnterJIT") == 0) {
// Found JIT entry frame. Unwind up to that point (i.e., force
// the stack walk to stop before the block of saved registers;
// note that it yields nondecreasing stack pointers), then restore
// the saved state.
uint32_t *vSP = reinterpret_cast<uint32_t*>(entry.stackAddress());
array.count += EHABIStackWalk(*mcontext,
/* stackBase = */ vSP,
sp_array + array.count,
pc_array + array.count,
array.size - array.count);
memset(&savedContext, 0, sizeof(savedContext));
// See also: struct EnterJITStack in js/src/jit/arm/Trampoline-arm.cpp
savedContext.arm_r4 = *vSP++;
savedContext.arm_r5 = *vSP++;
savedContext.arm_r6 = *vSP++;
savedContext.arm_r7 = *vSP++;
savedContext.arm_r8 = *vSP++;
savedContext.arm_r9 = *vSP++;
savedContext.arm_r10 = *vSP++;
savedContext.arm_fp = *vSP++;
savedContext.arm_lr = *vSP++;
savedContext.arm_sp = reinterpret_cast<uint32_t>(vSP);
savedContext.arm_pc = savedContext.arm_lr;
mcontext = &savedContext;
}
}
// Now unwind whatever's left (starting from either the last EnterJIT
// frame or, if no EnterJIT was found, the original registers).
array.count += EHABIStackWalk(*mcontext,
aProfile.GetStackTop(),
sp_array + array.count,
pc_array + array.count,
array.size - array.count);
mergeNativeBacktrace(aProfile, array);
}
示例6: mergeStacksIntoProfile
static
void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, NativeStack& aNativeStack)
{
PseudoStack* pseudoStack = aProfile.GetPseudoStack();
volatile StackEntry *pseudoFrames = pseudoStack->mStack;
uint32_t pseudoCount = pseudoStack->stackSize();
// Make a copy of the JS stack into a JSFrame array. This is necessary since,
// like the native stack, the JS stack is iterated youngest-to-oldest and we
// need to iterate oldest-to-youngest when adding entries to aProfile.
// Synchronous sampling reports an invalid buffer generation to
// ProfilingFrameIterator to avoid incorrectly resetting the generation of
// sampled JIT entries inside the JS engine. See note below concerning 'J'
// entries.
uint32_t startBufferGen;
if (aSample->isSamplingCurrentThread) {
startBufferGen = UINT32_MAX;
} else {
startBufferGen = aProfile.bufferGeneration();
}
uint32_t jsCount = 0;
#ifndef SPS_STANDALONE
JS::ProfilingFrameIterator::Frame jsFrames[1000];
// Only walk jit stack if profiling frame iterator is turned on.
if (pseudoStack->mRuntime && JS::IsProfilingEnabledForRuntime(pseudoStack->mRuntime)) {
AutoWalkJSStack autoWalkJSStack;
const uint32_t maxFrames = mozilla::ArrayLength(jsFrames);
if (aSample && autoWalkJSStack.walkAllowed) {
JS::ProfilingFrameIterator::RegisterState registerState;
registerState.pc = aSample->pc;
registerState.sp = aSample->sp;
#ifdef ENABLE_ARM_LR_SAVING
registerState.lr = aSample->lr;
#endif
JS::ProfilingFrameIterator jsIter(pseudoStack->mRuntime,
registerState,
startBufferGen);
for (; jsCount < maxFrames && !jsIter.done(); ++jsIter) {
// See note below regarding 'J' entries.
if (aSample->isSamplingCurrentThread || jsIter.isAsmJS()) {
uint32_t extracted = jsIter.extractStack(jsFrames, jsCount, maxFrames);
jsCount += extracted;
if (jsCount == maxFrames)
break;
} else {
mozilla::Maybe<JS::ProfilingFrameIterator::Frame> frame =
jsIter.getPhysicalFrameWithoutLabel();
if (frame.isSome())
jsFrames[jsCount++] = frame.value();
}
}
}
}
#endif
// Start the sample with a root entry.
aProfile.addTag(ProfileEntry('s', "(root)"));
// While the pseudo-stack array is ordered oldest-to-youngest, the JS and
// native arrays are ordered youngest-to-oldest. We must add frames to
// aProfile oldest-to-youngest. Thus, iterate over the pseudo-stack forwards
// and JS and native arrays backwards. Note: this means the terminating
// condition jsIndex and nativeIndex is being < 0.
uint32_t pseudoIndex = 0;
int32_t jsIndex = jsCount - 1;
int32_t nativeIndex = aNativeStack.count - 1;
uint8_t *lastPseudoCppStackAddr = nullptr;
// Iterate as long as there is at least one frame remaining.
while (pseudoIndex != pseudoCount || jsIndex >= 0 || nativeIndex >= 0) {
// There are 1 to 3 frames available. Find and add the oldest.
uint8_t *pseudoStackAddr = nullptr;
uint8_t *jsStackAddr = nullptr;
uint8_t *nativeStackAddr = nullptr;
if (pseudoIndex != pseudoCount) {
volatile StackEntry &pseudoFrame = pseudoFrames[pseudoIndex];
if (pseudoFrame.isCpp())
lastPseudoCppStackAddr = (uint8_t *) pseudoFrame.stackAddress();
#ifndef SPS_STANDALONE
// Skip any pseudo-stack JS frames which are marked isOSR
// Pseudostack frames are marked isOSR when the JS interpreter
// enters a jit frame on a loop edge (via on-stack-replacement,
// or OSR). To avoid both the pseudoframe and jit frame being
// recorded (and showing up twice), the interpreter marks the
// interpreter pseudostack entry with the OSR flag to ensure that
// it doesn't get counted.
if (pseudoFrame.isJs() && pseudoFrame.isOSR()) {
pseudoIndex++;
continue;
}
#endif
//.........这里部分代码省略.........
示例7: InplaceTick
void GeckoSampler::InplaceTick(TickSample* sample)
{
ThreadProfile& currThreadProfile = *sample->threadProfile;
currThreadProfile.addTag(ProfileEntry('T', currThreadProfile.ThreadId()));
if (sample) {
mozilla::TimeDuration delta = sample->timestamp - sStartTime;
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
}
PseudoStack* stack = currThreadProfile.GetPseudoStack();
#if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK) || \
defined(USE_LUL_STACKWALK)
if (mUseStackWalk) {
doNativeBacktrace(currThreadProfile, sample);
} else {
doSampleStackTrace(currThreadProfile, sample, mAddLeafAddresses);
}
#else
doSampleStackTrace(currThreadProfile, sample, mAddLeafAddresses);
#endif
// Don't process the PeudoStack's markers if we're
// synchronously sampling the current thread.
if (!sample->isSamplingCurrentThread) {
ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers();
while (pendingMarkersList && pendingMarkersList->peek()) {
ProfilerMarker* marker = pendingMarkersList->popHead();
currThreadProfile.addStoredMarker(marker);
currThreadProfile.addTag(ProfileEntry('m', marker));
}
}
#ifndef SPS_STANDALONE
if (sample && currThreadProfile.GetThreadResponsiveness()->HasData()) {
mozilla::TimeDuration delta = currThreadProfile.GetThreadResponsiveness()->GetUnresponsiveDuration(sample->timestamp);
currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
}
#endif
// rssMemory is equal to 0 when we are not recording.
if (sample && sample->rssMemory != 0) {
currThreadProfile.addTag(ProfileEntry('R', static_cast<double>(sample->rssMemory)));
}
// ussMemory is equal to 0 when we are not recording.
if (sample && sample->ussMemory != 0) {
currThreadProfile.addTag(ProfileEntry('U', static_cast<double>(sample->ussMemory)));
}
#if defined(XP_WIN)
if (mProfilePower) {
mIntelPowerGadget->TakeSample();
currThreadProfile.addTag(ProfileEntry('p', static_cast<double>(mIntelPowerGadget->GetTotalPackagePowerInWatts())));
}
#endif
if (sLastFrameNumber != sFrameNumber) {
currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
sLastFrameNumber = sFrameNumber;
}
}
示例8: GetPrimaryThreadProfile
// RUNS IN SIGHANDLER CONTEXT
void TableTicker::UnwinderTick(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();
/* This could fail, if no buffers are currently available, in which
case we must give up right away. We cannot wait for a buffer to
become available, as that risks deadlock. */
if (!utb)
return;
/* Manufacture the ProfileEntries that we will give to the unwinder
thread, and park them in |utb|. */
// Marker(s) come before the sample
PseudoStack* stack = currThreadProfile.GetPseudoStack();
for (int i = 0; stack->getMarker(i) != NULL; i++) {
utb__addEntry( utb, ProfileEntry('m', stack->getMarker(i)) );
}
stack->mQueueClearMarker = true;
bool recordSample = true;
if (mJankOnly) {
// if we are on a different event we can discard any temporary samples
// we've kept around
if (sLastSampledEventGeneration != sCurrentEventGeneration) {
// 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();
}
sLastSampledEventGeneration = sCurrentEventGeneration;
recordSample = false;
// only record the events when we have a we haven't seen a tracer
// event for 100ms
if (!sLastTracerEvent.IsNull()) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
if (delta.ToMilliseconds() > 100.0) {
recordSample = true;
}
}
}
// JRS 2012-Sept-27: this logic used to involve mUseStackWalk.
// That should be reinstated, but for the moment, use the
// settings in sUnwindMode and sUnwindInterval.
// Add a native-backtrace request, or add pseudo backtrace entries,
// or both.
switch (sUnwindMode) {
case UnwNATIVE: /* Native only */
// add a "do native stack trace now" hint. This will be actioned
// by the unwinder thread as it processes the entries in this
// sample.
utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'N'/*native-trace*/) );
break;
case UnwPSEUDO: /* Pseudo only */
/* Add into |utb|, the pseudo backtrace entries */
genPseudoBacktraceEntries(utb, stack, sample);
break;
case UnwCOMBINED: /* Both Native and Pseudo */
utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'N'/*native-trace*/) );
genPseudoBacktraceEntries(utb, stack, sample);
break;
case UnwINVALID:
default:
MOZ_CRASH();
}
if (recordSample) {
// add a "flush now" hint
utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'F'/*flush*/) );
}
// Add any extras
if (!sLastTracerEvent.IsNull() && sample) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
utb__addEntry( utb, ProfileEntry('r', delta.ToMilliseconds()) );
}
if (sample) {
TimeDuration delta = sample->timestamp - sStartTime;
utb__addEntry( utb, ProfileEntry('t', delta.ToMilliseconds()) );
}
if (sLastFrameNumber != sFrameNumber) {
utb__addEntry( utb, ProfileEntry('f', sFrameNumber) );
sLastFrameNumber = sFrameNumber;
}
/* So now we have, in |utb|, the complete set of entries we want to
//.........这里部分代码省略.........
示例9: mergeStacksIntoProfile
static
void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, NativeStack& aNativeStack)
{
PseudoStack* pseudoStack = aProfile.GetPseudoStack();
volatile StackEntry *pseudoFrames = pseudoStack->mStack;
uint32_t pseudoCount = pseudoStack->stackSize();
// Make a copy of the JS stack into a JSFrame array. This is necessary since,
// like the native stack, the JS stack is iterated youngest-to-oldest and we
// need to iterate oldest-to-youngest when adding entries to aProfile.
JSFrame jsFrames[1000];
uint32_t jsCount = 0;
if (aSample && pseudoStack->mRuntime) {
JS::ProfilingFrameIterator::RegisterState registerState;
registerState.pc = aSample->pc;
registerState.sp = aSample->sp;
#ifdef ENABLE_ARM_LR_SAVING
registerState.lr = aSample->lr;
#endif
JS::ProfilingFrameIterator jsIter(pseudoStack->mRuntime, registerState);
for (; jsCount < mozilla::ArrayLength(jsFrames) && !jsIter.done(); ++jsCount, ++jsIter) {
jsFrames[jsCount].stackAddress = jsIter.stackAddress();
jsFrames[jsCount].label = jsIter.label();
}
}
// Start the sample with a root entry.
aProfile.addTag(ProfileEntry('s', "(root)"));
// While the pseudo-stack array is ordered oldest-to-youngest, the JS and
// native arrays are ordered youngest-to-oldest. We must add frames to
// aProfile oldest-to-youngest. Thus, iterate over the pseudo-stack forwards
// and JS and native arrays backwards. Note: this means the terminating
// condition jsIndex and nativeIndex is being < 0.
uint32_t pseudoIndex = 0;
int32_t jsIndex = jsCount - 1;
int32_t nativeIndex = aNativeStack.count - 1;
// Iterate as long as there is at least one frame remaining.
while (pseudoIndex != pseudoCount || jsIndex >= 0 || nativeIndex >= 0) {
// There are 1 to 3 frames available. Find and add the oldest. Handle pseudo
// frames first, since there are two special cases that must be considered
// before everything else.
if (pseudoIndex != pseudoCount) {
volatile StackEntry &pseudoFrame = pseudoFrames[pseudoIndex];
// isJs pseudo-stack frames assume the stackAddress of the preceding isCpp
// pseudo-stack frame. If we arrive at an isJs pseudo frame, we've already
// encountered the preceding isCpp stack frame and it was oldest, we can
// assume the isJs frame is oldest without checking other frames.
if (pseudoFrame.isJs()) {
addPseudoEntry(pseudoFrame, aProfile, pseudoStack, nullptr);
pseudoIndex++;
continue;
}
// Currently, only asm.js frames use the JS stack and Ion/Baseline/Interp
// frames use the pseudo stack. In the optimized asm.js->Ion call path, no
// isCpp frame is pushed, leading to the callstack:
// old | pseudo isCpp | asm.js | pseudo isJs | new
// Since there is no interleaving isCpp pseudo frame between the asm.js
// and isJs pseudo frame, the above isJs logic will render the callstack:
// old | pseudo isCpp | pseudo isJs | asm.js | new
// which is wrong. To deal with this, a pseudo isCpp frame pushed right
// before entering asm.js flagged with StackEntry::ASMJS. When we see this
// flag, we first push all the asm.js frames (up to the next frame with a
// stackAddress) before pushing the isJs frames. There is no Ion->asm.js
// fast path, so we don't have to worry about asm.js->Ion->asm.js.
//
// (This and the above isJs special cases can be removed once all JS
// execution modes switch from the pseudo stack to the JS stack.)
if (pseudoFrame.hasFlag(StackEntry::ASMJS)) {
void *stopStackAddress = nullptr;
for (uint32_t i = pseudoIndex + 1; i != pseudoCount; i++) {
if (pseudoFrames[i].isCpp()) {
stopStackAddress = pseudoFrames[i].stackAddress();
break;
}
}
if (nativeIndex >= 0) {
stopStackAddress = std::max(stopStackAddress, aNativeStack.sp_array[nativeIndex]);
}
while (jsIndex >= 0 && jsFrames[jsIndex].stackAddress > stopStackAddress) {
addDynamicTag(aProfile, 'c', jsFrames[jsIndex].label);
jsIndex--;
}
pseudoIndex++;
continue;
}
// Finally, consider the normal case of a plain C++ pseudo-frame.
if ((jsIndex < 0 || pseudoFrame.stackAddress() > jsFrames[jsIndex].stackAddress) &&
(nativeIndex < 0 || pseudoFrame.stackAddress() > aNativeStack.sp_array[nativeIndex]))
{
// The (C++) pseudo-frame is the oldest.
//.........这里部分代码省略.........
示例10: GetThreadHandle
void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
{
#ifndef XP_MACOSX
uintptr_t thread = GetThreadHandle(aSample->threadProfile->GetPlatformData());
MOZ_ASSERT(thread);
#endif
void* pc_array[1000];
void* sp_array[1000];
PCArray array = {
pc_array,
sp_array,
mozilla::ArrayLength(pc_array),
0
};
// Start with the current function.
StackWalkCallback(aSample->pc, aSample->sp, &array);
uint32_t maxFrames = uint32_t(array.size - array.count);
#ifdef XP_MACOSX
pthread_t pt = GetProfiledThread(aSample->threadProfile->GetPlatformData());
void *stackEnd = reinterpret_cast<void*>(-1);
if (pt)
stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
nsresult rv = NS_OK;
if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
rv = FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0,
maxFrames, &array,
reinterpret_cast<void**>(aSample->fp), stackEnd);
#else
void *platformData = nullptr;
#ifdef XP_WIN
platformData = aSample->context;
#endif // XP_WIN
nsresult rv = NS_StackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
&array, thread, platformData);
#endif
if (NS_SUCCEEDED(rv)) {
aProfile.addTag(ProfileEntry('s', "(root)"));
PseudoStack* stack = aProfile.GetPseudoStack();
uint32_t pseudoStackPos = 0;
/* We have two stacks, the native C stack we extracted from unwinding,
* and the pseudostack we managed during execution. We want to consolidate
* the two in order. We do so by merging using the approximate stack address
* when each entry was push. When pushing JS entry we may not now the stack
* address in which case we have a NULL stack address in which case we assume
* that it follows immediatly the previous element.
*
* C Stack | Address -- Pseudo Stack | Address
* main() | 0x100 run_js() | 0x40
* start() | 0x80 jsCanvas() | NULL
* timer() | 0x50 drawLine() | NULL
* azure() | 0x10
*
* Merged: main(), start(), timer(), run_js(), jsCanvas(), drawLine(), azure()
*/
// i is the index in C stack starting at main and decreasing
// pseudoStackPos is the position in the Pseudo stack starting
// at the first frame (run_js in the example) and increasing.
for (size_t i = array.count; i > 0; --i) {
while (pseudoStackPos < stack->stackSize()) {
volatile StackEntry& entry = stack->mStack[pseudoStackPos];
if (entry.stackAddress() < array.sp_array[i-1] && entry.stackAddress())
break;
addProfileEntry(entry, aProfile, stack, array.array[0]);
pseudoStackPos++;
}
aProfile.addTag(ProfileEntry('l', (void*)array.array[i-1]));
}
}
}