зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 3923ce220df3 (bug 1380286) for hazard failures
This commit is contained in:
Родитель
8408f943c1
Коммит
965777ef3a
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include "ProfilerMarker.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
ProfileBuffer::ProfileBuffer(int aEntrySize)
|
||||
: mEntries(mozilla::MakeUnique<ProfileBufferEntry[]>(aEntrySize))
|
||||
, mWritePos(0)
|
||||
|
@ -57,6 +55,24 @@ ProfileBuffer::AddThreadIdEntry(int aThreadId, LastSample* aLS)
|
|||
AddEntry(ProfileBufferEntry::ThreadId(aThreadId));
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::AddDynamicStringEntry(const char* aStr)
|
||||
{
|
||||
size_t strLen = strlen(aStr) + 1; // +1 for the null terminator
|
||||
for (size_t j = 0; j < strLen; ) {
|
||||
// Store up to kNumChars characters in the entry.
|
||||
char chars[ProfileBufferEntry::kNumChars];
|
||||
size_t len = ProfileBufferEntry::kNumChars;
|
||||
if (j + len >= strLen) {
|
||||
len = strLen - j;
|
||||
}
|
||||
memcpy(chars, &aStr[j], len);
|
||||
j += ProfileBufferEntry::kNumChars;
|
||||
|
||||
AddEntry(ProfileBufferEntry::DynamicStringFragment(chars));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::AddStoredMarker(ProfilerMarker *aStoredMarker)
|
||||
{
|
||||
|
@ -64,51 +80,6 @@ ProfileBuffer::AddStoredMarker(ProfilerMarker *aStoredMarker)
|
|||
mStoredMarkers.insert(aStoredMarker);
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::CollectNativeLeafAddr(void* aAddr)
|
||||
{
|
||||
AddEntry(ProfileBufferEntry::NativeLeafAddr(aAddr));
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::CollectJitReturnAddr(void* aAddr)
|
||||
{
|
||||
AddEntry(ProfileBufferEntry::JitReturnAddr(aAddr));
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, int aLineNumber,
|
||||
const Maybe<js::ProfileEntry::Category>& aCategory)
|
||||
{
|
||||
AddEntry(ProfileBufferEntry::Label(aLabel));
|
||||
|
||||
if (aStr) {
|
||||
// Store the string using one or more DynamicStringFragment entries.
|
||||
size_t strLen = strlen(aStr) + 1; // +1 for the null terminator
|
||||
for (size_t j = 0; j < strLen; ) {
|
||||
// Store up to kNumChars characters in the entry.
|
||||
char chars[ProfileBufferEntry::kNumChars];
|
||||
size_t len = ProfileBufferEntry::kNumChars;
|
||||
if (j + len >= strLen) {
|
||||
len = strLen - j;
|
||||
}
|
||||
memcpy(chars, &aStr[j], len);
|
||||
j += ProfileBufferEntry::kNumChars;
|
||||
|
||||
AddEntry(ProfileBufferEntry::DynamicStringFragment(chars));
|
||||
}
|
||||
}
|
||||
|
||||
if (aLineNumber != -1) {
|
||||
AddEntry(ProfileBufferEntry::LineNumber(aLineNumber));
|
||||
}
|
||||
|
||||
if (aCategory.isSome()) {
|
||||
AddEntry(ProfileBufferEntry::Category(int(*aCategory)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProfileBuffer::DeleteExpiredStoredMarkers()
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
class ProfileBuffer final : public ProfilerStackCollector
|
||||
class ProfileBuffer final
|
||||
{
|
||||
public:
|
||||
explicit ProfileBuffer(int aEntrySize);
|
||||
|
@ -42,16 +42,9 @@ public:
|
|||
// record the resulting generation and index in |aLS| if it's non-null.
|
||||
void AddThreadIdEntry(int aThreadId, LastSample* aLS = nullptr);
|
||||
|
||||
virtual mozilla::Maybe<uint32_t> Generation() override
|
||||
{
|
||||
return mozilla::Some(mGeneration);
|
||||
}
|
||||
|
||||
virtual void CollectNativeLeafAddr(void* aAddr) override;
|
||||
virtual void CollectJitReturnAddr(void* aAddr) override;
|
||||
virtual void CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, int aLineNumber,
|
||||
const mozilla::Maybe<js::ProfileEntry::Category>& aCategory) override;
|
||||
// Add to the buffer a dynamic string. It'll be spread across one or more
|
||||
// DynamicStringFragment entries.
|
||||
void AddDynamicStringEntry(const char* aStr);
|
||||
|
||||
// Maximum size of a frameKey string that we'll handle.
|
||||
static const size_t kMaxFrameKeyLength = 512;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
//
|
||||
// - A "backtrace" sample is the simplest kind. It is done in response to an
|
||||
// API call (profiler_suspend_and_sample_thread()). It involves getting a
|
||||
// stack trace via a ProfilerStackCollector; it does not write to a
|
||||
// stack trace and passing it to a callback function; it does not write to a
|
||||
// ProfileBuffer. The sampling is done from off-thread, and so uses
|
||||
// SuspendAndSampleAndResumeThread() to get the register values.
|
||||
|
||||
|
@ -54,9 +54,7 @@
|
|||
#include "nsIXULRuntime.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsMemoryReporterManager.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsProfilerStartParams.h"
|
||||
#include "ProfilerParent.h"
|
||||
|
@ -659,31 +657,17 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
static bool
|
||||
IsChromeJSScript(JSScript* aScript)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
|
||||
nsIScriptSecurityManager* const secman =
|
||||
nsScriptSecurityManager::GetScriptSecurityManager();
|
||||
NS_ENSURE_TRUE(secman, false);
|
||||
|
||||
JSPrincipals* const principals = JS_GetScriptPrincipals(aScript);
|
||||
return secman->IsSystemPrincipal(nsJSPrincipals::get(principals));
|
||||
}
|
||||
|
||||
static void
|
||||
AddPseudoEntry(uint32_t aFeatures, NotNull<RacyThreadInfo*> aRacyInfo,
|
||||
const js::ProfileEntry& entry,
|
||||
ProfilerStackCollector& aCollector)
|
||||
AddPseudoEntry(PSLockRef aLock, NotNull<RacyThreadInfo*> aRacyInfo,
|
||||
const js::ProfileEntry& entry, ProfileBuffer& aBuffer)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
// WARNING: this function might be called while the profiler is inactive, and
|
||||
// cannot rely on ActivePS.
|
||||
|
||||
MOZ_ASSERT(entry.kind() == js::ProfileEntry::Kind::CPP_NORMAL ||
|
||||
entry.kind() == js::ProfileEntry::Kind::JS_NORMAL);
|
||||
|
||||
aBuffer.AddEntry(ProfileBufferEntry::Label(entry.label()));
|
||||
|
||||
const char* dynamicString = entry.dynamicString();
|
||||
int lineno = -1;
|
||||
|
||||
|
@ -691,11 +675,18 @@ AddPseudoEntry(uint32_t aFeatures, NotNull<RacyThreadInfo*> aRacyInfo,
|
|||
// |dynamicString|. Perhaps it shouldn't?
|
||||
|
||||
if (dynamicString) {
|
||||
bool isChromeJSEntry = false;
|
||||
// Adjust the dynamic string as necessary.
|
||||
if (ActivePS::FeaturePrivacy(aLock)) {
|
||||
dynamicString = "(private)";
|
||||
} else if (strlen(dynamicString) >= ProfileBuffer::kMaxFrameKeyLength) {
|
||||
dynamicString = "(too long)";
|
||||
}
|
||||
|
||||
// Store the string using one or more DynamicStringFragment entries.
|
||||
aBuffer.AddDynamicStringEntry(dynamicString);
|
||||
if (entry.isJs()) {
|
||||
JSScript* script = entry.script();
|
||||
if (script) {
|
||||
isChromeJSEntry = IsChromeJSScript(script);
|
||||
if (!entry.pc()) {
|
||||
// The JIT only allows the top-most entry to have a nullptr pc.
|
||||
MOZ_ASSERT(&entry == &aRacyInfo->entries[aRacyInfo->stackSize() - 1]);
|
||||
|
@ -706,14 +697,6 @@ AddPseudoEntry(uint32_t aFeatures, NotNull<RacyThreadInfo*> aRacyInfo,
|
|||
} else {
|
||||
lineno = entry.line();
|
||||
}
|
||||
|
||||
// Adjust the dynamic string as necessary.
|
||||
if (ProfilerFeature::HasPrivacy(aFeatures) && !isChromeJSEntry) {
|
||||
dynamicString = "(private)";
|
||||
} else if (strlen(dynamicString) >= ProfileBuffer::kMaxFrameKeyLength) {
|
||||
dynamicString = "(too long)";
|
||||
}
|
||||
|
||||
} else {
|
||||
// XXX: Bug 1010578. Don't assume a CPP entry and try to get the line for
|
||||
// js entries as well.
|
||||
|
@ -722,8 +705,11 @@ AddPseudoEntry(uint32_t aFeatures, NotNull<RacyThreadInfo*> aRacyInfo,
|
|||
}
|
||||
}
|
||||
|
||||
aCollector.CollectCodeLocation(entry.label(), dynamicString, lineno,
|
||||
Some(entry.category()));
|
||||
if (lineno != -1) {
|
||||
aBuffer.AddEntry(ProfileBufferEntry::LineNumber(lineno));
|
||||
}
|
||||
|
||||
aBuffer.AddEntry(ProfileBufferEntry::Category(int(entry.category())));
|
||||
}
|
||||
|
||||
// Setting MAX_NATIVE_FRAMES too high risks the unwinder wasting a lot of time
|
||||
|
@ -761,17 +747,12 @@ struct AutoWalkJSStack
|
|||
}
|
||||
};
|
||||
|
||||
// Merges the pseudo-stack, native stack, and JS stack, outputting the details
|
||||
// to aCollector.
|
||||
static void
|
||||
MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
||||
const ThreadInfo& aThreadInfo, const Registers& aRegs,
|
||||
const NativeStack& aNativeStack,
|
||||
ProfilerStackCollector& aCollector)
|
||||
MergeStacksIntoProfile(PSLockRef aLock, bool aIsSynchronous,
|
||||
const ThreadInfo& aThreadInfo, const Registers& aRegs,
|
||||
const NativeStack& aNativeStack, ProfileBuffer& aBuffer)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
// WARNING: this function might be called while the profiler is inactive, and
|
||||
// cannot rely on ActivePS.
|
||||
|
||||
NotNull<RacyThreadInfo*> racyInfo = aThreadInfo.RacyInfo();
|
||||
js::ProfileEntry* pseudoEntries = racyInfo->entries;
|
||||
|
@ -786,10 +767,10 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
// ProfilingFrameIterator to avoid incorrectly resetting the generation of
|
||||
// sampled JIT entries inside the JS engine. See note below concerning 'J'
|
||||
// entries.
|
||||
uint32_t startBufferGen = UINT32_MAX;
|
||||
if (!aIsSynchronous && aCollector.Generation().isSome()) {
|
||||
startBufferGen = *aCollector.Generation();
|
||||
}
|
||||
uint32_t startBufferGen;
|
||||
startBufferGen = aIsSynchronous
|
||||
? UINT32_MAX
|
||||
: aBuffer.mGeneration;
|
||||
uint32_t jsCount = 0;
|
||||
JS::ProfilingFrameIterator::Frame jsFrames[MAX_JS_FRAMES];
|
||||
|
||||
|
@ -901,7 +882,7 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
// Pseudo-frames with the CPP_MARKER_FOR_JS kind are just annotations and
|
||||
// should not be recorded in the profile.
|
||||
if (pseudoEntry.kind() != js::ProfileEntry::Kind::CPP_MARKER_FOR_JS) {
|
||||
AddPseudoEntry(aFeatures, racyInfo, pseudoEntry, aCollector);
|
||||
AddPseudoEntry(aLock, racyInfo, pseudoEntry, aBuffer);
|
||||
}
|
||||
pseudoIndex++;
|
||||
continue;
|
||||
|
@ -927,11 +908,13 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
// with stale JIT code return addresses.
|
||||
if (aIsSynchronous ||
|
||||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Wasm) {
|
||||
aCollector.CollectCodeLocation("", jsFrame.label, -1, Nothing());
|
||||
aBuffer.AddEntry(ProfileBufferEntry::Label(""));
|
||||
aBuffer.AddDynamicStringEntry(jsFrame.label);
|
||||
} else {
|
||||
MOZ_ASSERT(jsFrame.kind == JS::ProfilingFrameIterator::Frame_Ion ||
|
||||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Baseline);
|
||||
aCollector.CollectJitReturnAddr(jsFrames[jsIndex].returnAddress);
|
||||
aBuffer.AddEntry(
|
||||
ProfileBufferEntry::JitReturnAddr(jsFrames[jsIndex].returnAddress));
|
||||
}
|
||||
|
||||
jsIndex--;
|
||||
|
@ -943,7 +926,7 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
if (nativeStackAddr) {
|
||||
MOZ_ASSERT(nativeIndex >= 0);
|
||||
void* addr = (void*)aNativeStack.mPCs[nativeIndex];
|
||||
aCollector.CollectNativeLeafAddr(addr);
|
||||
aBuffer.AddEntry(ProfileBufferEntry::NativeLeafAddr(addr));
|
||||
}
|
||||
if (nativeIndex >= 0) {
|
||||
nativeIndex--;
|
||||
|
@ -954,11 +937,10 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
//
|
||||
// Do not do this for synchronous samples, which use their own
|
||||
// ProfileBuffers instead of the global one in CorePS.
|
||||
if (!aIsSynchronous && context && aCollector.Generation().isSome()) {
|
||||
MOZ_ASSERT(*aCollector.Generation() >= startBufferGen);
|
||||
uint32_t lapCount = *aCollector.Generation() - startBufferGen;
|
||||
JS::UpdateJSContextProfilerSampleBufferGen(context,
|
||||
*aCollector.Generation(),
|
||||
if (!aIsSynchronous && context) {
|
||||
MOZ_ASSERT(aBuffer.mGeneration >= startBufferGen);
|
||||
uint32_t lapCount = aBuffer.mGeneration - startBufferGen;
|
||||
JS::UpdateJSContextProfilerSampleBufferGen(context, aBuffer.mGeneration,
|
||||
lapCount);
|
||||
}
|
||||
}
|
||||
|
@ -983,8 +965,6 @@ DoNativeBacktrace(PSLockRef aLock, const ThreadInfo& aThreadInfo,
|
|||
const Registers& aRegs, NativeStack& aNativeStack)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
// WARNING: this function might be called while the profiler is inactive, and
|
||||
// cannot rely on ActivePS.
|
||||
|
||||
// Start with the current function. We use 0 as the frame number here because
|
||||
// the FramePointerStackWalk() and MozStackWalk() calls below will use 1..N.
|
||||
|
@ -1018,8 +998,6 @@ DoNativeBacktrace(PSLockRef aLock, const ThreadInfo& aThreadInfo,
|
|||
const Registers& aRegs, NativeStack& aNativeStack)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
// WARNING: this function might be called while the profiler is inactive, and
|
||||
// cannot rely on ActivePS.
|
||||
|
||||
const mcontext_t* mcontext = &aRegs.mContext->uc_mcontext;
|
||||
mcontext_t savedContext;
|
||||
|
@ -1099,8 +1077,6 @@ DoNativeBacktrace(PSLockRef aLock, const ThreadInfo& aThreadInfo,
|
|||
const Registers& aRegs, NativeStack& aNativeStack)
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
// WARNING: this function might be called while the profiler is inactive, and
|
||||
// cannot rely on ActivePS.
|
||||
|
||||
const mcontext_t* mc = &aRegs.mContext->uc_mcontext;
|
||||
|
||||
|
@ -1246,13 +1222,13 @@ DoSharedSample(PSLockRef aLock, bool aIsSynchronous,
|
|||
if (ActivePS::FeatureStackWalk(aLock)) {
|
||||
DoNativeBacktrace(aLock, aThreadInfo, aRegs, nativeStack);
|
||||
|
||||
MergeStacks(ActivePS::Features(aLock), aIsSynchronous, aThreadInfo, aRegs,
|
||||
nativeStack, aBuffer);
|
||||
MergeStacksIntoProfile(aLock, aIsSynchronous, aThreadInfo, aRegs,
|
||||
nativeStack, aBuffer);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MergeStacks(ActivePS::Features(aLock), aIsSynchronous, aThreadInfo, aRegs,
|
||||
nativeStack, aBuffer);
|
||||
MergeStacksIntoProfile(aLock, aIsSynchronous, aThreadInfo, aRegs,
|
||||
nativeStack, aBuffer);
|
||||
|
||||
if (ActivePS::FeatureLeaf(aLock)) {
|
||||
aBuffer.AddEntry(ProfileBufferEntry::NativeLeafAddr((void*)aRegs.mPC));
|
||||
|
@ -3070,62 +3046,5 @@ profiler_suspend_and_sample_thread(
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: aCollector's methods will be called while the target thread is paused.
|
||||
// Doing things in those methods like allocating -- which may try to claim
|
||||
// locks -- is a surefire way to deadlock.
|
||||
void
|
||||
profiler_suspend_and_sample_thread(int aThreadId,
|
||||
uint32_t aFeatures,
|
||||
ProfilerStackCollector& aCollector,
|
||||
bool aSampleNative /* = true */)
|
||||
{
|
||||
// Lock the profiler mutex
|
||||
PSAutoLock lock(gPSMutex);
|
||||
|
||||
const CorePS::ThreadVector& liveThreads = CorePS::LiveThreads(lock);
|
||||
for (uint32_t i = 0; i < liveThreads.size(); i++) {
|
||||
ThreadInfo* info = liveThreads.at(i);
|
||||
|
||||
if (info->ThreadId() == aThreadId) {
|
||||
if (info->IsMainThread()) {
|
||||
aCollector.SetIsMainThread();
|
||||
}
|
||||
|
||||
// Allocate the space for the native stack
|
||||
NativeStack nativeStack;
|
||||
|
||||
// Suspend, sample, and then resume the target thread.
|
||||
Sampler sampler(lock);
|
||||
sampler.SuspendAndSampleAndResumeThread(lock, *info,
|
||||
[&](const Registers& aRegs) {
|
||||
// The target thread is now suspended. Collect a native backtrace, and
|
||||
// call the callback.
|
||||
bool isSynchronous = false;
|
||||
#if defined(HAVE_NATIVE_UNWIND)
|
||||
if (aSampleNative) {
|
||||
DoNativeBacktrace(lock, *info, aRegs, nativeStack);
|
||||
|
||||
MergeStacks(aFeatures, isSynchronous, *info, aRegs, nativeStack,
|
||||
aCollector);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MergeStacks(aFeatures, isSynchronous, *info, aRegs, nativeStack,
|
||||
aCollector);
|
||||
|
||||
if (ProfilerFeature::HasLeaf(aFeatures)) {
|
||||
aCollector.CollectNativeLeafAddr((void*)aRegs.mPC);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// NOTE: Make sure to disable the sampler before it is destroyed, in case
|
||||
// the profiler is running at the same time.
|
||||
sampler.Disable(lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// END externally visible functions
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -81,7 +81,6 @@ if CONFIG['MOZ_GECKO_PROFILER']:
|
|||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/caps',
|
||||
'/docshell/base',
|
||||
'/ipc/chromium/src',
|
||||
'/mozglue/linker',
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -268,52 +267,11 @@ typedef void ProfilerStackCallback(void** aPCs, size_t aCount, bool aIsMainThrea
|
|||
// WARNING: The target thread is suspended during the callback. Do not try to
|
||||
// allocate or acquire any locks, or you could deadlock. The target thread will
|
||||
// have resumed by the time this function returns.
|
||||
//
|
||||
// XXX: this function is in the process of being replaced with the other profiler_suspend_and_sample_thread() function.
|
||||
PROFILER_FUNC_VOID(
|
||||
profiler_suspend_and_sample_thread(int aThreadId,
|
||||
const std::function<ProfilerStackCallback>& aCallback,
|
||||
bool aSampleNative = true))
|
||||
|
||||
// An object of this class is passed to profiler_suspend_and_sample_thread().
|
||||
// For each stack frame, one of the Collect methods will be called.
|
||||
class ProfilerStackCollector
|
||||
{
|
||||
public:
|
||||
// Some collectors need to worry about possibly overwriting previous
|
||||
// generations of data. If that's not an issue, this can return Nothing,
|
||||
// which is the default behaviour.
|
||||
virtual mozilla::Maybe<uint32_t> Generation() { return mozilla::Nothing(); }
|
||||
|
||||
// This method will be called once if the thread being suspended is the main
|
||||
// thread. Default behaviour is to do nothing.
|
||||
virtual void SetIsMainThread() {}
|
||||
|
||||
// WARNING: The target thread is suspended when the Collect methods are
|
||||
// called. Do not try to allocate or acquire any locks, or you could
|
||||
// deadlock. The target thread will have resumed by the time this function
|
||||
// returns.
|
||||
|
||||
virtual void CollectNativeLeafAddr(void* aAddr) = 0;
|
||||
|
||||
virtual void CollectJitReturnAddr(void* aAddr) = 0;
|
||||
|
||||
// aLabel is static and never null. aStr may be null. aLineNumber may be -1.
|
||||
virtual void CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, int aLineNumber,
|
||||
const mozilla::Maybe<js::ProfileEntry::Category>& aCategory) = 0;
|
||||
};
|
||||
|
||||
// This method suspends the thread identified by aThreadId, samples its
|
||||
// pseudo-stack, JS stack, and (optionally) native stack, passing the collected
|
||||
// frames into aCollector. aFeatures dictates which compiler features are used.
|
||||
// |Privacy| and |Leaf| are the only relevant ones.
|
||||
PROFILER_FUNC_VOID(
|
||||
profiler_suspend_and_sample_thread(int aThreadId,
|
||||
uint32_t aFeatures,
|
||||
ProfilerStackCollector& aCollector,
|
||||
bool aSampleNative = true))
|
||||
|
||||
struct ProfilerBacktraceDestructor
|
||||
{
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
|
|
|
@ -664,70 +664,3 @@ TEST(GeckoProfiler, Bug1355807)
|
|||
|
||||
profiler_stop();
|
||||
}
|
||||
|
||||
class GTestStackCollector final : public ProfilerStackCollector
|
||||
{
|
||||
public:
|
||||
GTestStackCollector()
|
||||
: mSetIsMainThread(0)
|
||||
, mFrames(0)
|
||||
{}
|
||||
|
||||
virtual void SetIsMainThread() { mSetIsMainThread++; }
|
||||
|
||||
virtual void CollectNativeLeafAddr(void* aAddr) { mFrames++; }
|
||||
virtual void CollectJitReturnAddr(void* aAddr) { mFrames++; }
|
||||
virtual void CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, int aLineNumber,
|
||||
const mozilla::Maybe<js::ProfileEntry::Category>& aCategory) { mFrames++; }
|
||||
|
||||
int mSetIsMainThread;
|
||||
int mFrames;
|
||||
};
|
||||
|
||||
void DoSuspendAndSample(int aTid, nsIThread* aThread)
|
||||
{
|
||||
aThread->Dispatch(
|
||||
NS_NewRunnableFunction(
|
||||
"GeckoProfiler_SuspendAndSample_Test::TestBody",
|
||||
[&]() {
|
||||
uint32_t features = ProfilerFeature::Leaf;
|
||||
GTestStackCollector collector;
|
||||
profiler_suspend_and_sample_thread(aTid, features, collector,
|
||||
/* sampleNative = */ true);
|
||||
|
||||
ASSERT_TRUE(collector.mSetIsMainThread == 1);
|
||||
ASSERT_TRUE(collector.mFrames > 5); // approximate; must be > 0
|
||||
}),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
TEST(GeckoProfiler, SuspendAndSample)
|
||||
{
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = NS_NewNamedThread("GeckoProfGTest", getter_AddRefs(thread));
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
int tid = Thread::GetCurrentId();
|
||||
|
||||
ASSERT_TRUE(!profiler_is_active());
|
||||
|
||||
// Suspend and sample while the profiler is inactive.
|
||||
DoSuspendAndSample(tid, thread);
|
||||
|
||||
uint32_t features = ProfilerFeature::JS | ProfilerFeature::Threads;
|
||||
const char* filters[] = { "GeckoMain", "Compositor" };
|
||||
|
||||
profiler_start(PROFILER_DEFAULT_ENTRIES, PROFILER_DEFAULT_INTERVAL,
|
||||
features, filters, MOZ_ARRAY_LENGTH(filters));
|
||||
|
||||
ASSERT_TRUE(profiler_is_active());
|
||||
|
||||
// Suspend and sample while the profiler is active.
|
||||
DoSuspendAndSample(tid, thread);
|
||||
|
||||
profiler_stop();
|
||||
|
||||
ASSERT_TRUE(!profiler_is_active());
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче