mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 06:15:43 +00:00
Bug 1434965 - Remove OnStackFrameKey and solve frame canonicalization differently. r=njn
MozReview-Commit-ID: DITzwF94U64 --HG-- extra : rebase_source : 8d5c40b2bdcd22ee87ca8429d95b026309f932d5
This commit is contained in:
parent
e53f99f34a
commit
4e334139e5
@ -277,13 +277,13 @@ bool UniqueStacks::FrameKey::operator==(const FrameKey& aOther) const
|
||||
}
|
||||
|
||||
UniqueStacks::StackKey
|
||||
UniqueStacks::BeginStack(const OnStackFrameKey& aFrame)
|
||||
UniqueStacks::BeginStack(const FrameKey& aFrame)
|
||||
{
|
||||
return StackKey(GetOrAddFrameIndex(aFrame));
|
||||
}
|
||||
|
||||
UniqueStacks::StackKey
|
||||
UniqueStacks::AppendFrame(const StackKey& aStack, const OnStackFrameKey& aFrame)
|
||||
UniqueStacks::AppendFrame(const StackKey& aStack, const FrameKey& aFrame)
|
||||
{
|
||||
return StackKey(aStack, GetOrAddStackIndex(aStack), GetOrAddFrameIndex(aFrame));
|
||||
}
|
||||
@ -311,7 +311,6 @@ uint32_t UniqueStacks::FrameKey::Hash() const
|
||||
|
||||
UniqueStacks::UniqueStacks(JSContext* aContext)
|
||||
: mContext(aContext)
|
||||
, mFrameCount(0)
|
||||
{
|
||||
mFrameTableWriter.StartBareList();
|
||||
mStackTableWriter.StartBareList();
|
||||
@ -331,54 +330,59 @@ uint32_t UniqueStacks::GetOrAddStackIndex(const StackKey& aStack)
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t UniqueStacks::GetOrAddFrameIndex(const OnStackFrameKey& aFrame)
|
||||
MOZ_MUST_USE nsTArray<UniqueStacks::FrameKey>
|
||||
UniqueStacks::GetOrAddJITFrameKeysForAddress(void* aJITAddress)
|
||||
{
|
||||
nsTArray<FrameKey>& frameKeys =
|
||||
*mAddressToJITFrameKeysMap.LookupOrAdd(aJITAddress);
|
||||
|
||||
if (frameKeys.IsEmpty()) {
|
||||
MOZ_RELEASE_ASSERT(mContext);
|
||||
for (JS::ProfiledFrameHandle handle : JS::GetProfiledFrames(mContext,
|
||||
aJITAddress)) {
|
||||
// JIT frames with the same canonical address should be treated as the
|
||||
// same frame, so set the frame key's address to the canonical address.
|
||||
FrameKey frameKey(handle.canonicalAddress(), frameKeys.Length());
|
||||
MaybeAddJITFrameIndex(frameKey, handle);
|
||||
frameKeys.AppendElement(frameKey);
|
||||
}
|
||||
MOZ_ASSERT(frameKeys.Length() > 0);
|
||||
}
|
||||
|
||||
// Return a copy of the array.
|
||||
return nsTArray<FrameKey>(frameKeys);
|
||||
}
|
||||
|
||||
void
|
||||
UniqueStacks::MaybeAddJITFrameIndex(const FrameKey& aFrame,
|
||||
const JS::ProfiledFrameHandle& aJITFrame)
|
||||
{
|
||||
uint32_t index;
|
||||
if (mFrameToIndexMap.Get(aFrame, &index)) {
|
||||
MOZ_ASSERT(index < mFrameCount);
|
||||
MOZ_ASSERT(index < mFrameToIndexMap.Count());
|
||||
return;
|
||||
}
|
||||
|
||||
index = mFrameToIndexMap.Count();
|
||||
mFrameToIndexMap.Put(aFrame, index);
|
||||
StreamJITFrame(aJITFrame);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
UniqueStacks::GetOrAddFrameIndex(const FrameKey& aFrame)
|
||||
{
|
||||
uint32_t index;
|
||||
if (mFrameToIndexMap.Get(aFrame, &index)) {
|
||||
MOZ_ASSERT(index < mFrameToIndexMap.Count());
|
||||
return index;
|
||||
}
|
||||
|
||||
// If aFrame isn't canonical, forward it to the canonical frame's index.
|
||||
if (aFrame.mJITFrameHandle) {
|
||||
void* canonicalAddr = aFrame.mJITFrameHandle->canonicalAddress();
|
||||
if (canonicalAddr != *aFrame.mJITAddress) {
|
||||
OnStackFrameKey canonicalKey(canonicalAddr, *aFrame.mJITDepth, *aFrame.mJITFrameHandle);
|
||||
uint32_t canonicalIndex = GetOrAddFrameIndex(canonicalKey);
|
||||
mFrameToIndexMap.Put(aFrame, canonicalIndex);
|
||||
return canonicalIndex;
|
||||
}
|
||||
// A manual count is used instead of mFrameToIndexMap.Count() due to
|
||||
// forwarding of canonical JIT frames above.
|
||||
index = mFrameCount++;
|
||||
mFrameToIndexMap.Put(aFrame, index);
|
||||
StreamJITFrame(*aFrame.mJITFrameHandle);
|
||||
} else {
|
||||
index = mFrameCount++;
|
||||
mFrameToIndexMap.Put(aFrame, index);
|
||||
StreamNonJITFrame(aFrame);
|
||||
}
|
||||
index = mFrameToIndexMap.Count();
|
||||
mFrameToIndexMap.Put(aFrame, index);
|
||||
StreamNonJITFrame(aFrame);
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t UniqueStacks::LookupJITFrameDepth(void* aAddr)
|
||||
{
|
||||
uint32_t depth;
|
||||
|
||||
auto it = mJITFrameDepthMap.find(aAddr);
|
||||
if (it != mJITFrameDepthMap.end()) {
|
||||
depth = it->second;
|
||||
MOZ_ASSERT(depth > 0);
|
||||
return depth;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UniqueStacks::AddJITFrameDepth(void* aAddr, unsigned depth)
|
||||
{
|
||||
mJITFrameDepthMap[aAddr] = depth;
|
||||
}
|
||||
|
||||
void UniqueStacks::SpliceFrameTableElements(SpliceableJSONWriter& aWriter)
|
||||
{
|
||||
mFrameTableWriter.EndBareList();
|
||||
@ -741,7 +745,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
}
|
||||
|
||||
UniqueStacks::StackKey stack =
|
||||
aUniqueStacks.BeginStack(UniqueStacks::OnStackFrameKey("(root)"));
|
||||
aUniqueStacks.BeginStack(UniqueStacks::FrameKey("(root)"));
|
||||
|
||||
int numFrames = 0;
|
||||
while (e.Has()) {
|
||||
@ -753,7 +757,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
unsigned long long pc = (unsigned long long)(uintptr_t)e.Get().u.mPtr;
|
||||
char buf[20];
|
||||
SprintfLiteral(buf, "%#llx", pc);
|
||||
stack = aUniqueStacks.AppendFrame(stack, UniqueStacks::OnStackFrameKey(buf));
|
||||
stack = aUniqueStacks.AppendFrame(stack, UniqueStacks::FrameKey(buf));
|
||||
e.Next();
|
||||
|
||||
} else if (e.Get().IsLabel()) {
|
||||
@ -793,7 +797,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
}
|
||||
strbuf[kMaxFrameKeyLength - 1] = '\0';
|
||||
|
||||
UniqueStacks::OnStackFrameKey frameKey(strbuf.get());
|
||||
UniqueStacks::FrameKey frameKey(strbuf.get());
|
||||
|
||||
if (e.Has() && e.Get().IsLineNumber()) {
|
||||
frameKey.mLine = Some(unsigned(e.Get().u.mInt));
|
||||
@ -812,21 +816,10 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
|
||||
// A JIT frame may expand to multiple frames due to inlining.
|
||||
void* pc = e.Get().u.mPtr;
|
||||
unsigned depth = aUniqueStacks.LookupJITFrameDepth(pc);
|
||||
if (depth == 0) {
|
||||
MOZ_RELEASE_ASSERT(aContext);
|
||||
for (JS::ProfiledFrameHandle handle : JS::GetProfiledFrames(aContext, pc)) {
|
||||
UniqueStacks::OnStackFrameKey frameKey(pc, depth, handle);
|
||||
stack = aUniqueStacks.AppendFrame(stack, frameKey);
|
||||
depth++;
|
||||
}
|
||||
MOZ_ASSERT(depth > 0);
|
||||
aUniqueStacks.AddJITFrameDepth(pc, depth);
|
||||
} else {
|
||||
for (unsigned i = 0; i < depth; i++) {
|
||||
UniqueStacks::OnStackFrameKey inlineFrameKey(pc, i);
|
||||
stack = aUniqueStacks.AppendFrame(stack, inlineFrameKey);
|
||||
}
|
||||
nsTArray<UniqueStacks::FrameKey> frameKeys =
|
||||
aUniqueStacks.GetOrAddJITFrameKeysForAddress(pc);
|
||||
for (const UniqueStacks::FrameKey& frameKey : frameKeys) {
|
||||
stack = aUniqueStacks.AppendFrame(stack, frameKey);
|
||||
}
|
||||
|
||||
e.Next();
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "gtest/MozGtestFriend.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class ProfilerMarker;
|
||||
|
||||
@ -216,32 +217,6 @@ public:
|
||||
uint32_t mHash;
|
||||
};
|
||||
|
||||
// A FrameKey that holds a scoped reference to a JIT FrameHandle.
|
||||
struct MOZ_STACK_CLASS OnStackFrameKey : public FrameKey {
|
||||
explicit OnStackFrameKey(const char* aLocation)
|
||||
: FrameKey(aLocation)
|
||||
, mJITFrameHandle(nullptr)
|
||||
{ }
|
||||
|
||||
OnStackFrameKey(const OnStackFrameKey& aToCopy)
|
||||
: FrameKey(aToCopy)
|
||||
, mJITFrameHandle(aToCopy.mJITFrameHandle)
|
||||
{ }
|
||||
|
||||
const JS::ProfiledFrameHandle* mJITFrameHandle;
|
||||
|
||||
OnStackFrameKey(void* aJITAddress, unsigned aJITDepth)
|
||||
: FrameKey(aJITAddress, aJITDepth)
|
||||
, mJITFrameHandle(nullptr)
|
||||
{ }
|
||||
|
||||
OnStackFrameKey(void* aJITAddress, unsigned aJITDepth,
|
||||
const JS::ProfiledFrameHandle& aJITFrameHandle)
|
||||
: FrameKey(aJITAddress, aJITDepth)
|
||||
, mJITFrameHandle(&aJITFrameHandle)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct StackKey {
|
||||
mozilla::Maybe<uint32_t> mPrefixStackIndex;
|
||||
uint32_t mFrameIndex;
|
||||
@ -276,21 +251,27 @@ public:
|
||||
explicit UniqueStacks(JSContext* aContext);
|
||||
|
||||
// Return a StackKey for aFrame as the stack's root frame (no prefix).
|
||||
MOZ_MUST_USE StackKey BeginStack(const OnStackFrameKey& aFrame);
|
||||
MOZ_MUST_USE StackKey BeginStack(const FrameKey& aFrame);
|
||||
|
||||
// Return a new StackKey that is obtained by appending aFrame to aStack.
|
||||
MOZ_MUST_USE StackKey AppendFrame(const StackKey& aStack,
|
||||
const OnStackFrameKey& aFrame);
|
||||
const FrameKey& aFrame);
|
||||
|
||||
MOZ_MUST_USE uint32_t GetOrAddFrameIndex(const OnStackFrameKey& aFrame);
|
||||
MOZ_MUST_USE nsTArray<FrameKey>
|
||||
GetOrAddJITFrameKeysForAddress(void* aJITAddress);
|
||||
|
||||
MOZ_MUST_USE uint32_t GetOrAddFrameIndex(const FrameKey& aFrame);
|
||||
MOZ_MUST_USE uint32_t GetOrAddStackIndex(const StackKey& aStack);
|
||||
|
||||
uint32_t LookupJITFrameDepth(void* aAddr);
|
||||
void AddJITFrameDepth(void* aAddr, unsigned depth);
|
||||
void SpliceFrameTableElements(SpliceableJSONWriter& aWriter);
|
||||
void SpliceStackTableElements(SpliceableJSONWriter& aWriter);
|
||||
|
||||
private:
|
||||
// Make sure that there exists a frame index for aFrame, and if there isn't
|
||||
// one already, create one and call StreamJITFrame for the frame.
|
||||
void MaybeAddJITFrameIndex(const FrameKey& aFrame,
|
||||
const JS::ProfiledFrameHandle& aJITFrame);
|
||||
|
||||
void StreamNonJITFrame(const FrameKey& aFrame);
|
||||
void StreamJITFrame(const JS::ProfiledFrameHandle& aJITFrame);
|
||||
void StreamStack(const StackKey& aStack);
|
||||
@ -302,17 +283,14 @@ private:
|
||||
JSContext* mContext;
|
||||
|
||||
// To avoid incurring JitcodeGlobalTable lookup costs for every JIT frame,
|
||||
// we cache the depth of frames keyed by JIT code address. If an address a
|
||||
// maps to a depth d, then frames keyed by a for depths 0 to d are
|
||||
// guaranteed to be in mFrameToIndexMap.
|
||||
std::map<void*, uint32_t> mJITFrameDepthMap;
|
||||
// we cache the frame keys of frames keyed by JIT code address. All FrameKeys
|
||||
// in mAddressToJITFrameKeysMap are guaranteed to be in mFrameToIndexMap.
|
||||
nsClassHashtable<nsPtrHashKey<void>, nsTArray<FrameKey>> mAddressToJITFrameKeysMap;
|
||||
|
||||
uint32_t mFrameCount;
|
||||
SpliceableChunkedJSONWriter mFrameTableWriter;
|
||||
nsDataHashtable<nsGenericHashKey<FrameKey>, uint32_t> mFrameToIndexMap;
|
||||
|
||||
SpliceableChunkedJSONWriter mStackTableWriter;
|
||||
|
||||
nsDataHashtable<nsGenericHashKey<StackKey>, uint32_t> mStackToIndexMap;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user