ProfilerBacktrace.h (5896B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef __PROFILER_BACKTRACE_H 8 #define __PROFILER_BACKTRACE_H 9 10 #include "mozilla/ProfileChunkedBuffer.h" 11 #include "mozilla/UniquePtr.h" 12 13 #include <string> 14 15 namespace mozilla { 16 17 class TimeStamp; 18 19 namespace baseprofiler { 20 21 class ProfileBuffer; 22 class SpliceableJSONWriter; 23 class ThreadInfo; 24 class UniqueStacks; 25 26 // ProfilerBacktrace encapsulates a synchronous sample. 27 // It can work with a ProfileBuffer and/or a ProfileChunkedBuffer (if both, they 28 // must already be linked together). The ProfileChunkedBuffer contains all the 29 // data; the ProfileBuffer is not strictly needed, only provide it if it is 30 // already available at the call site. 31 // And these buffers can either be: 32 // - owned here, so that the ProfilerBacktrace object can be kept for later 33 // use), OR 34 // - referenced through pointers (in cases where the backtrace is immediately 35 // streamed out, so we only need temporary references to external buffers); 36 // these pointers may be null for empty backtraces. 37 class ProfilerBacktrace { 38 public: 39 // Take ownership of external buffers and use them to keep, and to stream a 40 // backtrace. If a ProfileBuffer is given, its underlying chunked buffer must 41 // be provided as well. 42 explicit ProfilerBacktrace( 43 const char* aName, 44 UniquePtr<ProfileChunkedBuffer> aProfileChunkedBufferStorage, 45 UniquePtr<ProfileBuffer> aProfileBufferStorageOrNull = nullptr); 46 47 // Take pointers to external buffers and use them to stream a backtrace. 48 // If null, the backtrace is effectively empty. 49 // If both are provided, they must already be connected. 50 explicit ProfilerBacktrace( 51 const char* aName, 52 ProfileChunkedBuffer* aExternalProfileChunkedBufferOrNull = nullptr, 53 ProfileBuffer* aExternalProfileBufferOrNull = nullptr); 54 55 ~ProfilerBacktrace(); 56 57 [[nodiscard]] bool IsEmpty() const { 58 return !mProfileChunkedBuffer || 59 ProfileBufferEntryWriter::Serializer<ProfileChunkedBuffer>::Bytes( 60 *mProfileChunkedBuffer) <= ULEB128Size(0u); 61 } 62 63 // ProfilerBacktraces' stacks are deduplicated in the context of the 64 // profile that contains the backtrace as a marker payload. 65 // 66 // That is, markers that contain backtraces should not need their own stack, 67 // frame, and string tables. They should instead reuse their parent 68 // profile's tables. 69 BaseProfilerThreadId StreamJSON(SpliceableJSONWriter& aWriter, 70 const TimeStamp& aProcessStartTime, 71 UniqueStacks& aUniqueStacks); 72 73 private: 74 // Used to de/serialize a ProfilerBacktrace. 75 friend ProfileBufferEntryWriter::Serializer<ProfilerBacktrace>; 76 friend ProfileBufferEntryReader::Deserializer<ProfilerBacktrace>; 77 78 std::string mName; 79 80 // `ProfileChunkedBuffer` in which `mProfileBuffer` stores its data; must be 81 // located before `mProfileBuffer` so that it's destroyed after. 82 UniquePtr<ProfileChunkedBuffer> mOptionalProfileChunkedBufferStorage; 83 // If null, there is no need to check mProfileBuffer's (if present) underlying 84 // buffer because this is done when constructed. 85 ProfileChunkedBuffer* mProfileChunkedBuffer; 86 87 UniquePtr<ProfileBuffer> mOptionalProfileBufferStorage; 88 ProfileBuffer* mProfileBuffer; 89 }; 90 91 } // namespace baseprofiler 92 93 // Format: [ UniquePtr<BlockRingsBuffer> | name ] 94 // Initial len==0 marks a nullptr or empty backtrace. 95 template <> 96 struct ProfileBufferEntryWriter::Serializer<baseprofiler::ProfilerBacktrace> { 97 static Length Bytes(const baseprofiler::ProfilerBacktrace& aBacktrace) { 98 if (!aBacktrace.mProfileChunkedBuffer) { 99 // No buffer. 100 return ULEB128Size(0u); 101 } 102 auto bufferBytes = SumBytes(*aBacktrace.mProfileChunkedBuffer); 103 if (bufferBytes <= ULEB128Size(0u)) { 104 // Empty buffer. 105 return ULEB128Size(0u); 106 } 107 return bufferBytes + SumBytes(aBacktrace.mName); 108 } 109 110 static void Write(ProfileBufferEntryWriter& aEW, 111 const baseprofiler::ProfilerBacktrace& aBacktrace) { 112 if (!aBacktrace.mProfileChunkedBuffer || 113 SumBytes(*aBacktrace.mProfileChunkedBuffer) <= ULEB128Size(0u)) { 114 // No buffer, or empty buffer. 115 aEW.WriteULEB128(0u); 116 return; 117 } 118 aEW.WriteObject(*aBacktrace.mProfileChunkedBuffer); 119 aEW.WriteObject(aBacktrace.mName); 120 } 121 }; 122 123 template <typename Destructor> 124 struct ProfileBufferEntryWriter::Serializer< 125 UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>> { 126 static Length Bytes(const UniquePtr<baseprofiler::ProfilerBacktrace, 127 Destructor>& aBacktrace) { 128 if (!aBacktrace) { 129 // Null backtrace pointer (treated like an empty backtrace). 130 return ULEB128Size(0u); 131 } 132 return SumBytes(*aBacktrace); 133 } 134 135 static void Write(ProfileBufferEntryWriter& aEW, 136 const UniquePtr<baseprofiler::ProfilerBacktrace, 137 Destructor>& aBacktrace) { 138 if (!aBacktrace) { 139 // Null backtrace pointer (treated like an empty backtrace). 140 aEW.WriteULEB128(0u); 141 return; 142 } 143 aEW.WriteObject(*aBacktrace); 144 } 145 }; 146 147 template <typename Destructor> 148 struct ProfileBufferEntryReader::Deserializer< 149 UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>> { 150 static void ReadInto( 151 ProfileBufferEntryReader& aER, 152 UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>& aBacktrace) { 153 aBacktrace = Read(aER); 154 } 155 156 static UniquePtr<baseprofiler::ProfilerBacktrace, Destructor> Read( 157 ProfileBufferEntryReader& aER); 158 }; 159 160 } // namespace mozilla 161 162 #endif // __PROFILER_BACKTRACE_H