From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- mozglue/baseprofiler/core/ProfilerBacktrace.h | 162 ++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 mozglue/baseprofiler/core/ProfilerBacktrace.h (limited to 'mozglue/baseprofiler/core/ProfilerBacktrace.h') diff --git a/mozglue/baseprofiler/core/ProfilerBacktrace.h b/mozglue/baseprofiler/core/ProfilerBacktrace.h new file mode 100644 index 0000000000..0b5b69e738 --- /dev/null +++ b/mozglue/baseprofiler/core/ProfilerBacktrace.h @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __PROFILER_BACKTRACE_H +#define __PROFILER_BACKTRACE_H + +#include "mozilla/ProfileChunkedBuffer.h" +#include "mozilla/UniquePtr.h" + +#include + +namespace mozilla { + +class TimeStamp; + +namespace baseprofiler { + +class ProfileBuffer; +class SpliceableJSONWriter; +class ThreadInfo; +class UniqueStacks; + +// ProfilerBacktrace encapsulates a synchronous sample. +// It can work with a ProfileBuffer and/or a ProfileChunkedBuffer (if both, they +// must already be linked together). The ProfileChunkedBuffer contains all the +// data; the ProfileBuffer is not strictly needed, only provide it if it is +// already available at the call site. +// And these buffers can either be: +// - owned here, so that the ProfilerBacktrace object can be kept for later +// use), OR +// - referenced through pointers (in cases where the backtrace is immediately +// streamed out, so we only need temporary references to external buffers); +// these pointers may be null for empty backtraces. +class ProfilerBacktrace { + public: + // Take ownership of external buffers and use them to keep, and to stream a + // backtrace. If a ProfileBuffer is given, its underlying chunked buffer must + // be provided as well. + explicit ProfilerBacktrace( + const char* aName, + UniquePtr aProfileChunkedBufferStorage, + UniquePtr aProfileBufferStorageOrNull = nullptr); + + // Take pointers to external buffers and use them to stream a backtrace. + // If null, the backtrace is effectively empty. + // If both are provided, they must already be connected. + explicit ProfilerBacktrace( + const char* aName, + ProfileChunkedBuffer* aExternalProfileChunkedBufferOrNull = nullptr, + ProfileBuffer* aExternalProfileBufferOrNull = nullptr); + + ~ProfilerBacktrace(); + + [[nodiscard]] bool IsEmpty() const { + return !mProfileChunkedBuffer || + ProfileBufferEntryWriter::Serializer::Bytes( + *mProfileChunkedBuffer) <= ULEB128Size(0u); + } + + // ProfilerBacktraces' stacks are deduplicated in the context of the + // profile that contains the backtrace as a marker payload. + // + // That is, markers that contain backtraces should not need their own stack, + // frame, and string tables. They should instead reuse their parent + // profile's tables. + BaseProfilerThreadId StreamJSON(SpliceableJSONWriter& aWriter, + const TimeStamp& aProcessStartTime, + UniqueStacks& aUniqueStacks); + + private: + // Used to de/serialize a ProfilerBacktrace. + friend ProfileBufferEntryWriter::Serializer; + friend ProfileBufferEntryReader::Deserializer; + + std::string mName; + + // `ProfileChunkedBuffer` in which `mProfileBuffer` stores its data; must be + // located before `mProfileBuffer` so that it's destroyed after. + UniquePtr mOptionalProfileChunkedBufferStorage; + // If null, there is no need to check mProfileBuffer's (if present) underlying + // buffer because this is done when constructed. + ProfileChunkedBuffer* mProfileChunkedBuffer; + + UniquePtr mOptionalProfileBufferStorage; + ProfileBuffer* mProfileBuffer; +}; + +} // namespace baseprofiler + +// Format: [ UniquePtr | name ] +// Initial len==0 marks a nullptr or empty backtrace. +template <> +struct ProfileBufferEntryWriter::Serializer { + static Length Bytes(const baseprofiler::ProfilerBacktrace& aBacktrace) { + if (!aBacktrace.mProfileChunkedBuffer) { + // No buffer. + return ULEB128Size(0u); + } + auto bufferBytes = SumBytes(*aBacktrace.mProfileChunkedBuffer); + if (bufferBytes <= ULEB128Size(0u)) { + // Empty buffer. + return ULEB128Size(0u); + } + return bufferBytes + SumBytes(aBacktrace.mName); + } + + static void Write(ProfileBufferEntryWriter& aEW, + const baseprofiler::ProfilerBacktrace& aBacktrace) { + if (!aBacktrace.mProfileChunkedBuffer || + SumBytes(*aBacktrace.mProfileChunkedBuffer) <= ULEB128Size(0u)) { + // No buffer, or empty buffer. + aEW.WriteULEB128(0u); + return; + } + aEW.WriteObject(*aBacktrace.mProfileChunkedBuffer); + aEW.WriteObject(aBacktrace.mName); + } +}; + +template +struct ProfileBufferEntryWriter::Serializer< + UniquePtr> { + static Length Bytes(const UniquePtr& aBacktrace) { + if (!aBacktrace) { + // Null backtrace pointer (treated like an empty backtrace). + return ULEB128Size(0u); + } + return SumBytes(*aBacktrace); + } + + static void Write(ProfileBufferEntryWriter& aEW, + const UniquePtr& aBacktrace) { + if (!aBacktrace) { + // Null backtrace pointer (treated like an empty backtrace). + aEW.WriteULEB128(0u); + return; + } + aEW.WriteObject(*aBacktrace); + } +}; + +template +struct ProfileBufferEntryReader::Deserializer< + UniquePtr> { + static void ReadInto( + ProfileBufferEntryReader& aER, + UniquePtr& aBacktrace) { + aBacktrace = Read(aER); + } + + static UniquePtr Read( + ProfileBufferEntryReader& aER); +}; + +} // namespace mozilla + +#endif // __PROFILER_BACKTRACE_H -- cgit v1.2.3