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/. */
7 #ifndef __PROFILER_BACKTRACE_H
8 #define __PROFILER_BACKTRACE_H
10 #include "ProfileBuffer.h"
12 #include "mozilla/ProfileBufferEntrySerialization.h"
13 #include "mozilla/UniquePtrExtensions.h"
18 class ProfilerCodeAddressService
;
23 class ProfileChunkedBuffer
;
25 namespace baseprofiler
{
26 class SpliceableJSONWriter
;
27 } // namespace baseprofiler
28 } // namespace mozilla
30 // ProfilerBacktrace encapsulates a synchronous sample.
31 // It can work with a ProfileBuffer and/or a ProfileChunkedBuffer (if both, they
32 // must already be linked together). The ProfileChunkedBuffer contains all the
33 // data; the ProfileBuffer is not strictly needed, only provide it if it is
34 // already available at the call site.
35 // And these buffers can either be:
36 // - owned here, so that the ProfilerBacktrace object can be kept for later
38 // - referenced through pointers (in cases where the backtrace is immediately
39 // streamed out, so we only need temporary references to external buffers);
40 // these pointers may be null for empty backtraces.
41 class ProfilerBacktrace
{
43 // Take ownership of external buffers and use them to keep, and to stream a
44 // backtrace. If a ProfileBuffer is given, its underlying chunked buffer must
45 // be provided as well.
46 explicit ProfilerBacktrace(
48 mozilla::UniquePtr
<mozilla::ProfileChunkedBuffer
>
49 aProfileChunkedBufferStorage
,
50 mozilla::UniquePtr
<ProfileBuffer
> aProfileBufferStorageOrNull
= nullptr);
52 // Take pointers to external buffers and use them to stream a backtrace.
53 // If null, the backtrace is effectively empty.
54 // If both are provided, they must already be connected.
55 explicit ProfilerBacktrace(
57 mozilla::ProfileChunkedBuffer
* aExternalProfileChunkedBufferOrNull
=
59 ProfileBuffer
* aExternalProfileBufferOrNull
= nullptr);
63 [[nodiscard
]] bool IsEmpty() const {
64 return !mProfileChunkedBuffer
||
65 mozilla::ProfileBufferEntryWriter::Serializer
<
66 mozilla::ProfileChunkedBuffer
>::Bytes(*mProfileChunkedBuffer
) <=
67 mozilla::ULEB128Size(0u);
70 // ProfilerBacktraces' stacks are deduplicated in the context of the
71 // profile that contains the backtrace as a marker payload.
73 // That is, markers that contain backtraces should not need their own stack,
74 // frame, and string tables. They should instead reuse their parent
76 ProfilerThreadId
StreamJSON(
77 mozilla::baseprofiler::SpliceableJSONWriter
& aWriter
,
78 const mozilla::TimeStamp
& aProcessStartTime
, UniqueStacks
& aUniqueStacks
);
81 // Used to serialize a ProfilerBacktrace.
82 friend struct mozilla::ProfileBufferEntryWriter::Serializer
<
84 friend struct mozilla::ProfileBufferEntryReader::Deserializer
<
89 // `ProfileChunkedBuffer` in which `mProfileBuffer` stores its data; must be
90 // located before `mProfileBuffer` so that it's destroyed after.
91 mozilla::UniquePtr
<mozilla::ProfileChunkedBuffer
>
92 mOptionalProfileChunkedBufferStorage
;
93 // If null, there is no need to check mProfileBuffer's (if present) underlying
94 // buffer because this is done when constructed.
95 mozilla::ProfileChunkedBuffer
* mProfileChunkedBuffer
;
97 mozilla::UniquePtr
<ProfileBuffer
> mOptionalProfileBufferStorage
;
98 ProfileBuffer
* mProfileBuffer
;
103 // Format: [ UniquePtr<BlockRingsBuffer> | name ]
104 // Initial len==0 marks a nullptr or empty backtrace.
106 struct mozilla::ProfileBufferEntryWriter::Serializer
<ProfilerBacktrace
> {
107 static Length
Bytes(const ProfilerBacktrace
& aBacktrace
) {
108 if (!aBacktrace
.mProfileChunkedBuffer
) {
110 return ULEB128Size(0u);
112 auto bufferBytes
= SumBytes(*aBacktrace
.mProfileChunkedBuffer
);
113 if (bufferBytes
<= ULEB128Size(0u)) {
115 return ULEB128Size(0u);
117 return bufferBytes
+ SumBytes(aBacktrace
.mName
);
120 static void Write(mozilla::ProfileBufferEntryWriter
& aEW
,
121 const ProfilerBacktrace
& aBacktrace
) {
122 if (!aBacktrace
.mProfileChunkedBuffer
||
123 SumBytes(*aBacktrace
.mProfileChunkedBuffer
) <= ULEB128Size(0u)) {
124 // No buffer, or empty buffer.
125 aEW
.WriteULEB128(0u);
128 aEW
.WriteObject(*aBacktrace
.mProfileChunkedBuffer
);
129 aEW
.WriteObject(aBacktrace
.mName
);
133 template <typename Destructor
>
134 struct mozilla::ProfileBufferEntryWriter::Serializer
<
135 mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
>> {
137 const mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
>& aBacktrace
) {
139 // Null backtrace pointer (treated like an empty backtrace).
140 return ULEB128Size(0u);
142 return SumBytes(*aBacktrace
);
146 mozilla::ProfileBufferEntryWriter
& aEW
,
147 const mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
>& aBacktrace
) {
149 // Null backtrace pointer (treated like an empty backtrace).
150 aEW
.WriteULEB128(0u);
153 aEW
.WriteObject(*aBacktrace
);
157 template <typename Destructor
>
158 struct mozilla::ProfileBufferEntryReader::Deserializer
<
159 mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
>> {
160 static void ReadInto(
161 mozilla::ProfileBufferEntryReader
& aER
,
162 mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
>& aBacktrace
) {
163 aBacktrace
= Read(aER
);
166 static mozilla::UniquePtr
<ProfilerBacktrace
, Destructor
> Read(
167 mozilla::ProfileBufferEntryReader
& aER
) {
168 auto profileChunkedBuffer
=
169 aER
.ReadObject
<UniquePtr
<ProfileChunkedBuffer
>>();
170 if (!profileChunkedBuffer
) {
174 !profileChunkedBuffer
->IsThreadSafe(),
175 "ProfilerBacktrace only stores non-thread-safe ProfileChunkedBuffers");
176 std::string name
= aER
.ReadObject
<std::string
>();
177 return UniquePtr
<ProfilerBacktrace
, Destructor
>{
178 new ProfilerBacktrace(name
.c_str(), std::move(profileChunkedBuffer
))};
182 } // namespace mozilla
184 #endif // __PROFILER_BACKTRACE_H