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:
Gerald Squelart 2019-09-18 01:19:40 +00:00
Родитель 0de7cb4c2e
Коммит ac26c5d9f5
8 изменённых файлов: 200 добавлений и 6 удалений

Просмотреть файл

@ -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