зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1576554 - {S,Des}erializer<ProfilerBacktrace> - r=gregtatum
Markers may contain backtraces, so we need to be able to de/serialize them. This involves de/serializing the underyling `BlocksRingBuffer`. Differential Revision: https://phabricator.services.mozilla.com/D43426 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0de7cb4c2e
Коммит
ac26c5d9f5
|
@ -31,6 +31,11 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer, PowerOfTwo32 aCapacity)
|
|||
mEntries.Set(aCapacity);
|
||||
}
|
||||
|
||||
ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
|
||||
// Assume the given buffer is not empty.
|
||||
MOZ_ASSERT(mEntries.BufferLength().isSome());
|
||||
}
|
||||
|
||||
ProfileBuffer::~ProfileBuffer() {
|
||||
while (mStoredMarkers.peek()) {
|
||||
delete mStoredMarkers.popHead();
|
||||
|
|
|
@ -30,10 +30,14 @@ class ProfileBuffer final {
|
|||
using BlockIndex = BlocksRingBuffer::BlockIndex;
|
||||
|
||||
// ProfileBuffer constructor
|
||||
// @param aBuffer The BlocksRingBuffer to use as buffer manager.
|
||||
// @param aBuffer The empty BlocksRingBuffer to use as buffer manager.
|
||||
// @param aCapacity The capacity of the buffer in memory.
|
||||
ProfileBuffer(BlocksRingBuffer& aBuffer, PowerOfTwo32 aCapacity);
|
||||
|
||||
// ProfileBuffer constructor
|
||||
// @param aBuffer The pre-filled BlocksRingBuffer to use as buffer manager.
|
||||
explicit ProfileBuffer(BlocksRingBuffer& aBuffer);
|
||||
|
||||
~ProfileBuffer();
|
||||
|
||||
bool IsThreadSafe() const { return mEntries.IsThreadSafe(); }
|
||||
|
|
|
@ -32,6 +32,8 @@ ProfilerBacktrace::ProfilerBacktrace(
|
|||
MOZ_ASSERT(
|
||||
!!mProfileBuffer,
|
||||
"ProfilerBacktrace only takes a non-null UniquePtr<ProfileBuffer>");
|
||||
MOZ_ASSERT(!mBlocksRingBuffer->IsThreadSafe(),
|
||||
"ProfilerBacktrace only takes a non-thread-safe BlocksRingBuffer");
|
||||
}
|
||||
|
||||
ProfilerBacktrace::~ProfilerBacktrace() {}
|
||||
|
@ -51,6 +53,28 @@ void ProfilerBacktrace::StreamJSON(SpliceableJSONWriter& aWriter,
|
|||
}
|
||||
|
||||
} // namespace baseprofiler
|
||||
|
||||
// static
|
||||
template <typename Destructor>
|
||||
UniquePtr<baseprofiler::ProfilerBacktrace, Destructor> BlocksRingBuffer::
|
||||
Deserializer<UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>>::Read(
|
||||
BlocksRingBuffer::EntryReader& aER) {
|
||||
auto blocksRingBuffer = aER.ReadObject<UniquePtr<BlocksRingBuffer>>();
|
||||
if (!blocksRingBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(!blocksRingBuffer->IsThreadSafe(),
|
||||
"ProfilerBacktrace only stores non-thread-safe BlocksRingBuffers");
|
||||
int threadId = aER.ReadObject<int>();
|
||||
std::string name = aER.ReadObject<std::string>();
|
||||
auto profileBuffer =
|
||||
MakeUnique<baseprofiler::ProfileBuffer>(*blocksRingBuffer);
|
||||
return UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>{
|
||||
new baseprofiler::ProfilerBacktrace(name.c_str(), threadId,
|
||||
std::move(blocksRingBuffer),
|
||||
std::move(profileBuffer))};
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZ_BASE_PROFILER
|
||||
|
|
|
@ -40,8 +40,9 @@ class ProfilerBacktrace {
|
|||
UniqueStacks& aUniqueStacks);
|
||||
|
||||
private:
|
||||
ProfilerBacktrace(const ProfilerBacktrace&);
|
||||
ProfilerBacktrace& operator=(const ProfilerBacktrace&);
|
||||
// Used to de/serialize a ProfilerBacktrace.
|
||||
friend struct BlocksRingBuffer::Serializer<ProfilerBacktrace>;
|
||||
friend struct BlocksRingBuffer::Deserializer<ProfilerBacktrace>;
|
||||
|
||||
UniqueFreePtr<char> mName;
|
||||
int mThreadId;
|
||||
|
@ -52,6 +53,77 @@ class ProfilerBacktrace {
|
|||
};
|
||||
|
||||
} // namespace baseprofiler
|
||||
|
||||
// Format: [ UniquePtr<BlockRingsBuffer> | threadId | name ]
|
||||
// Initial len==0 marks a nullptr or empty backtrace.
|
||||
template <>
|
||||
struct BlocksRingBuffer::Serializer<baseprofiler::ProfilerBacktrace> {
|
||||
static Length Bytes(const baseprofiler::ProfilerBacktrace& aBacktrace) {
|
||||
if (!aBacktrace.mProfileBuffer) {
|
||||
// No backtrace buffer.
|
||||
return ULEB128Size<Length>(0);
|
||||
}
|
||||
auto bufferBytes = SumBytes(*aBacktrace.mBlocksRingBuffer);
|
||||
if (bufferBytes == 0) {
|
||||
// Empty backtrace buffer.
|
||||
return ULEB128Size<Length>(0);
|
||||
}
|
||||
return bufferBytes +
|
||||
SumBytes(aBacktrace.mThreadId,
|
||||
WrapBlocksRingBufferUnownedCString(aBacktrace.mName.get()));
|
||||
}
|
||||
|
||||
static void Write(EntryWriter& aEW,
|
||||
const baseprofiler::ProfilerBacktrace& aBacktrace) {
|
||||
if (!aBacktrace.mProfileBuffer ||
|
||||
SumBytes(aBacktrace.mBlocksRingBuffer) == 0) {
|
||||
// No backtrace buffer, or it is empty.
|
||||
aEW.WriteULEB128<Length>(0);
|
||||
return;
|
||||
}
|
||||
aEW.WriteObject(aBacktrace.mBlocksRingBuffer);
|
||||
aEW.WriteObject(aBacktrace.mThreadId);
|
||||
aEW.WriteObject(WrapBlocksRingBufferUnownedCString(aBacktrace.mName.get()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Destructor>
|
||||
struct BlocksRingBuffer::Serializer<
|
||||
UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>> {
|
||||
static Length Bytes(const UniquePtr<baseprofiler::ProfilerBacktrace,
|
||||
Destructor>& aBacktrace) {
|
||||
if (!aBacktrace) {
|
||||
// Null backtrace pointer (treated like an empty backtrace).
|
||||
return ULEB128Size<Length>(0);
|
||||
}
|
||||
return SumBytes(*aBacktrace);
|
||||
}
|
||||
|
||||
static void Write(EntryWriter& aEW,
|
||||
const UniquePtr<baseprofiler::ProfilerBacktrace,
|
||||
Destructor>& aBacktrace) {
|
||||
if (!aBacktrace) {
|
||||
// Null backtrace pointer (treated like an empty backtrace).
|
||||
aEW.WriteULEB128<Length>(0);
|
||||
return;
|
||||
}
|
||||
aEW.WriteObject(*aBacktrace);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Destructor>
|
||||
struct BlocksRingBuffer::Deserializer<
|
||||
UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>> {
|
||||
static void ReadInto(
|
||||
EntryReader& aER,
|
||||
UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>& aBacktrace) {
|
||||
aBacktrace = Read(aER);
|
||||
}
|
||||
|
||||
static UniquePtr<baseprofiler::ProfilerBacktrace, Destructor> Read(
|
||||
EntryReader& aER);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // __PROFILER_BACKTRACE_H
|
||||
|
|
|
@ -31,6 +31,11 @@ ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer, PowerOfTwo32 aCapacity)
|
|||
mEntries.Set(aCapacity);
|
||||
}
|
||||
|
||||
ProfileBuffer::ProfileBuffer(BlocksRingBuffer& aBuffer) : mEntries(aBuffer) {
|
||||
// Assume the given buffer is not empty.
|
||||
MOZ_ASSERT(mEntries.BufferLength().isSome());
|
||||
}
|
||||
|
||||
ProfileBuffer::~ProfileBuffer() {
|
||||
while (mStoredMarkers.peek()) {
|
||||
delete mStoredMarkers.popHead();
|
||||
|
|
|
@ -27,11 +27,15 @@ class ProfileBuffer final {
|
|||
using BlockIndex = mozilla::BlocksRingBuffer::BlockIndex;
|
||||
|
||||
// ProfileBuffer constructor
|
||||
// @param aBuffer The BlocksRingBuffer to use as buffer manager.
|
||||
// @param aBuffer The empty BlocksRingBuffer to use as buffer manager.
|
||||
// @param aCapacity The capacity of the buffer.
|
||||
ProfileBuffer(mozilla::BlocksRingBuffer& aBuffer,
|
||||
mozilla::PowerOfTwo32 aCapacity);
|
||||
|
||||
// ProfileBuffer constructor
|
||||
// @param aBuffer The pre-filled BlocksRingBuffer to use as buffer manager.
|
||||
explicit ProfileBuffer(mozilla::BlocksRingBuffer& aBuffer);
|
||||
|
||||
~ProfileBuffer();
|
||||
|
||||
bool IsThreadSafe() const { return mEntries.IsThreadSafe(); }
|
||||
|
|
|
@ -26,6 +26,8 @@ ProfilerBacktrace::ProfilerBacktrace(
|
|||
MOZ_ASSERT(
|
||||
!!mProfileBuffer,
|
||||
"ProfilerBacktrace only takes a non-null UniquePtr<ProfileBuffer>");
|
||||
MOZ_ASSERT(!mBlocksRingBuffer->IsThreadSafe(),
|
||||
"ProfilerBacktrace only takes a non-thread-safe BlocksRingBuffer");
|
||||
}
|
||||
|
||||
ProfilerBacktrace::~ProfilerBacktrace() { MOZ_COUNT_DTOR(ProfilerBacktrace); }
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef __PROFILER_BACKTRACE_H
|
||||
#define __PROFILER_BACKTRACE_H
|
||||
|
||||
#include "ProfileBuffer.h"
|
||||
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
||||
class ProfileBuffer;
|
||||
|
@ -39,8 +41,9 @@ class ProfilerBacktrace {
|
|||
UniqueStacks& aUniqueStacks);
|
||||
|
||||
private:
|
||||
ProfilerBacktrace(const ProfilerBacktrace&);
|
||||
ProfilerBacktrace& operator=(const ProfilerBacktrace&);
|
||||
// Used to serialize a ProfilerBacktrace.
|
||||
friend struct BlocksRingBuffer::Serializer<ProfilerBacktrace>;
|
||||
friend struct BlocksRingBuffer::Deserializer<ProfilerBacktrace>;
|
||||
|
||||
mozilla::UniqueFreePtr<char> mName;
|
||||
int mThreadId;
|
||||
|
@ -50,4 +53,79 @@ class ProfilerBacktrace {
|
|||
mozilla::UniquePtr<ProfileBuffer> mProfileBuffer;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Format: [ UniquePtr<BlockRingsBuffer> | threadId | name ]
|
||||
// Initial len==0 marks a nullptr or empty backtrace.
|
||||
template <>
|
||||
struct BlocksRingBuffer::Serializer<ProfilerBacktrace> {
|
||||
static Length Bytes(const ProfilerBacktrace& aBacktrace) {
|
||||
if (!aBacktrace.mProfileBuffer) {
|
||||
return 1;
|
||||
}
|
||||
auto bufferBytes = SumBytes(*aBacktrace.mBlocksRingBuffer);
|
||||
if (bufferBytes == 0) {
|
||||
return 1;
|
||||
}
|
||||
return bufferBytes +
|
||||
SumBytes(aBacktrace.mThreadId,
|
||||
WrapBlocksRingBufferUnownedCString(aBacktrace.mName.get()));
|
||||
}
|
||||
static void Write(EntryWriter& aEW, const ProfilerBacktrace& aBacktrace) {
|
||||
if (!aBacktrace.mProfileBuffer ||
|
||||
SumBytes(*aBacktrace.mBlocksRingBuffer) == 0) {
|
||||
aEW.WriteULEB128(0u);
|
||||
return;
|
||||
}
|
||||
aEW.WriteObject(*aBacktrace.mBlocksRingBuffer);
|
||||
aEW.WriteObject(aBacktrace.mThreadId);
|
||||
aEW.WriteObject(WrapBlocksRingBufferUnownedCString(aBacktrace.mName.get()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Destructor>
|
||||
struct BlocksRingBuffer::Serializer<UniquePtr<ProfilerBacktrace, Destructor>> {
|
||||
static Length Bytes(
|
||||
const UniquePtr<ProfilerBacktrace, Destructor>& aBacktrace) {
|
||||
if (!aBacktrace) {
|
||||
return 1;
|
||||
}
|
||||
return SumBytes(*aBacktrace);
|
||||
}
|
||||
static void Write(
|
||||
EntryWriter& aEW,
|
||||
const UniquePtr<ProfilerBacktrace, Destructor>& aBacktrace) {
|
||||
if (!aBacktrace) {
|
||||
aEW.WriteULEB128(0u);
|
||||
return;
|
||||
}
|
||||
aEW.WriteObject(*aBacktrace);
|
||||
}
|
||||
};
|
||||
template <typename Destructor>
|
||||
struct BlocksRingBuffer::Deserializer<
|
||||
UniquePtr<ProfilerBacktrace, Destructor>> {
|
||||
static void ReadInto(EntryReader& aER,
|
||||
UniquePtr<ProfilerBacktrace, Destructor>& aBacktrace) {
|
||||
aBacktrace = Read(aER);
|
||||
}
|
||||
static UniquePtr<ProfilerBacktrace, Destructor> Read(EntryReader& aER) {
|
||||
auto blocksRingBuffer = aER.ReadObject<UniquePtr<BlocksRingBuffer>>();
|
||||
if (!blocksRingBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(
|
||||
!blocksRingBuffer->IsThreadSafe(),
|
||||
"ProfilerBacktrace only stores non-thread-safe BlocksRingBuffers");
|
||||
int threadId = aER.ReadObject<int>();
|
||||
std::string name = aER.ReadObject<std::string>();
|
||||
auto profileBuffer = MakeUnique<ProfileBuffer>(*blocksRingBuffer);
|
||||
return UniquePtr<ProfilerBacktrace, Destructor>{new ProfilerBacktrace(
|
||||
name.c_str(), threadId, std::move(blocksRingBuffer),
|
||||
std::move(profileBuffer))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // __PROFILER_BACKTRACE_H
|
||||
|
|
Загрузка…
Ссылка в новой задаче