xref: /aosp_15_r20/external/cronet/base/debug/allocation_trace.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_DEBUG_ALLOCATION_TRACE_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_DEBUG_ALLOCATION_TRACE_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <algorithm>
9*6777b538SAndroid Build Coastguard Worker #include <array>
10*6777b538SAndroid Build Coastguard Worker #include <atomic>
11*6777b538SAndroid Build Coastguard Worker #include <bit>
12*6777b538SAndroid Build Coastguard Worker #include <cstdint>
13*6777b538SAndroid Build Coastguard Worker 
14*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/notification_data.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/debug/debugging_buildflags.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr_exclusion.h"
20*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace base::debug::tracer {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker // Number of traces that can be stored. This number must be a power of two to
25*6777b538SAndroid Build Coastguard Worker // allow for fast computation of modulo.
26*6777b538SAndroid Build Coastguard Worker constexpr size_t kMaximumNumberOfMemoryOperationTraces = (1 << 15);
27*6777b538SAndroid Build Coastguard Worker // Number of frames stored for each operation. Probably the lower frames
28*6777b538SAndroid Build Coastguard Worker // represent the memory allocation system. Hence, we store more frames to
29*6777b538SAndroid Build Coastguard Worker // increase chances of having a meaningful trace of the path that caused the
30*6777b538SAndroid Build Coastguard Worker // allocation or free.
31*6777b538SAndroid Build Coastguard Worker constexpr size_t kStackTraceSize = 16;
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker // The type of an operation stored in the recorder.
34*6777b538SAndroid Build Coastguard Worker enum class OperationType {
35*6777b538SAndroid Build Coastguard Worker   // The state of an operation record before calling any of the initialization
36*6777b538SAndroid Build Coastguard Worker   // functions.
37*6777b538SAndroid Build Coastguard Worker   kNone = 0,
38*6777b538SAndroid Build Coastguard Worker   // The record represents an allocation operation.
39*6777b538SAndroid Build Coastguard Worker   kAllocation,
40*6777b538SAndroid Build Coastguard Worker   // The record represents a free operation.
41*6777b538SAndroid Build Coastguard Worker   kFree,
42*6777b538SAndroid Build Coastguard Worker };
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker using StackTraceContainer = std::array<const void*, kStackTraceSize>;
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker // The record for a single operation. A record can represent any type of
47*6777b538SAndroid Build Coastguard Worker // operation, allocation or free, but not at the same time.
48*6777b538SAndroid Build Coastguard Worker //
49*6777b538SAndroid Build Coastguard Worker // A record protects itself from concurrent initializations. If a thread B calls
50*6777b538SAndroid Build Coastguard Worker // any of the Initialize*-functions while another thread A is currently
51*6777b538SAndroid Build Coastguard Worker // initializing, B's invocations shall immediately return |false| without
52*6777b538SAndroid Build Coastguard Worker // interfering with thread A.
53*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT OperationRecord {
54*6777b538SAndroid Build Coastguard Worker  public:
55*6777b538SAndroid Build Coastguard Worker   constexpr OperationRecord() = default;
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker   OperationRecord(const OperationRecord&) = delete;
58*6777b538SAndroid Build Coastguard Worker   OperationRecord& operator=(const OperationRecord&) = delete;
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   // Is the record currently being taken?
61*6777b538SAndroid Build Coastguard Worker   bool IsRecording() const;
62*6777b538SAndroid Build Coastguard Worker 
63*6777b538SAndroid Build Coastguard Worker   OperationType GetOperationType() const;
64*6777b538SAndroid Build Coastguard Worker   // The address allocated or freed.
65*6777b538SAndroid Build Coastguard Worker   const void* GetAddress() const;
66*6777b538SAndroid Build Coastguard Worker   // Number of allocated bytes. Returns 0 for free operations.
67*6777b538SAndroid Build Coastguard Worker   size_t GetSize() const;
68*6777b538SAndroid Build Coastguard Worker   // The stacktrace as taken by the Initialize*-functions.
69*6777b538SAndroid Build Coastguard Worker   const StackTraceContainer& GetStackTrace() const;
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   // Initialize the record with data for another operation. Data from any
72*6777b538SAndroid Build Coastguard Worker   // previous operation will be silently overwritten. These functions are
73*6777b538SAndroid Build Coastguard Worker   // declared ALWAYS_INLINE to minimize pollution of the recorded stack trace.
74*6777b538SAndroid Build Coastguard Worker   //
75*6777b538SAndroid Build Coastguard Worker   // Both functions return false in case no record was taken, i.e. if another
76*6777b538SAndroid Build Coastguard Worker   // thread is capturing.
InitializeFree(const void * freed_address)77*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE bool InitializeFree(const void* freed_address) {
78*6777b538SAndroid Build Coastguard Worker     return InitializeOperationRecord(freed_address, 0, OperationType::kFree);
79*6777b538SAndroid Build Coastguard Worker   }
80*6777b538SAndroid Build Coastguard Worker 
InitializeAllocation(const void * allocated_address,size_t allocated_size)81*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE bool InitializeAllocation(const void* allocated_address,
82*6777b538SAndroid Build Coastguard Worker                                           size_t allocated_size) {
83*6777b538SAndroid Build Coastguard Worker     return InitializeOperationRecord(allocated_address, allocated_size,
84*6777b538SAndroid Build Coastguard Worker                                      OperationType::kAllocation);
85*6777b538SAndroid Build Coastguard Worker   }
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker  private:
88*6777b538SAndroid Build Coastguard Worker   // Initialize a record with the given data. Return true if the record was
89*6777b538SAndroid Build Coastguard Worker   // initialized successfully, false if no record was taken, i.e. if another
90*6777b538SAndroid Build Coastguard Worker   // thread is capturing.
91*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE bool InitializeOperationRecord(const void* address,
92*6777b538SAndroid Build Coastguard Worker                                                size_t size,
93*6777b538SAndroid Build Coastguard Worker                                                OperationType operation_type);
94*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE void StoreStackTrace();
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker   // The stack trace taken in one of the Initialize* functions.
97*6777b538SAndroid Build Coastguard Worker   StackTraceContainer stack_trace_ = {};
98*6777b538SAndroid Build Coastguard Worker   // The number of allocated bytes.
99*6777b538SAndroid Build Coastguard Worker   size_t size_ = 0;
100*6777b538SAndroid Build Coastguard Worker   // The address that was allocated or freed.
101*6777b538SAndroid Build Coastguard Worker   // We use a raw C++ pointer instead of base::raw_ptr for performance
102*6777b538SAndroid Build Coastguard Worker   // reasons.
103*6777b538SAndroid Build Coastguard Worker   // - In the recorder we only store pointers, we never allocate or free on
104*6777b538SAndroid Build Coastguard Worker   //   our own.
105*6777b538SAndroid Build Coastguard Worker   // - Storing is the hot path. base::raw_ptr::operator== may perform sanity
106*6777b538SAndroid Build Coastguard Worker   //   checks which do not make sense in our case (otherwise the allocated
107*6777b538SAndroid Build Coastguard Worker   //   address would have been quirky)
108*6777b538SAndroid Build Coastguard Worker   RAW_PTR_EXCLUSION const void* address_ = nullptr;
109*6777b538SAndroid Build Coastguard Worker   // The type of the operation that was performed. In the course of making a
110*6777b538SAndroid Build Coastguard Worker   // record, this value is reset to |OperationType::kNone| and later set to
111*6777b538SAndroid Build Coastguard Worker   // the operation type specific value, so if the process crashes whilst writing
112*6777b538SAndroid Build Coastguard Worker   // the record, it's marked as empty. To prevent the compiler from optimizing
113*6777b538SAndroid Build Coastguard Worker   // away the initial reset, this value is marked as volatile.
114*6777b538SAndroid Build Coastguard Worker   volatile OperationType operation_type_ = OperationType::kNone;
115*6777b538SAndroid Build Coastguard Worker   // Is the record currently being taken from another thread? Used to prevent
116*6777b538SAndroid Build Coastguard Worker   // concurrent writes to the same record.
117*6777b538SAndroid Build Coastguard Worker   //
118*6777b538SAndroid Build Coastguard Worker   // The value is mutable since pre C++20 there is no const getter in
119*6777b538SAndroid Build Coastguard Worker   // atomic_flag. All ways to get the value involve setting it.
120*6777b538SAndroid Build Coastguard Worker   // TODO(https://crbug.com/1284275): Remove mutable and make IsRecording() use
121*6777b538SAndroid Build Coastguard Worker   // atomic_flag::test();
122*6777b538SAndroid Build Coastguard Worker   mutable std::atomic_flag is_recording_ = ATOMIC_FLAG_INIT;
123*6777b538SAndroid Build Coastguard Worker };
124*6777b538SAndroid Build Coastguard Worker 
InitializeOperationRecord(const void * address,size_t size,OperationType operation_type)125*6777b538SAndroid Build Coastguard Worker ALWAYS_INLINE bool OperationRecord::InitializeOperationRecord(
126*6777b538SAndroid Build Coastguard Worker     const void* address,
127*6777b538SAndroid Build Coastguard Worker     size_t size,
128*6777b538SAndroid Build Coastguard Worker     OperationType operation_type) {
129*6777b538SAndroid Build Coastguard Worker   if (is_recording_.test_and_set(std::memory_order_acquire)) {
130*6777b538SAndroid Build Coastguard Worker     return false;
131*6777b538SAndroid Build Coastguard Worker   }
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker   operation_type_ = operation_type;
134*6777b538SAndroid Build Coastguard Worker   StoreStackTrace();
135*6777b538SAndroid Build Coastguard Worker   address_ = address;
136*6777b538SAndroid Build Coastguard Worker   size_ = size;
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   is_recording_.clear(std::memory_order_release);
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   return true;
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker 
StoreStackTrace()143*6777b538SAndroid Build Coastguard Worker ALWAYS_INLINE void OperationRecord::StoreStackTrace() {
144*6777b538SAndroid Build Coastguard Worker   stack_trace_.fill(nullptr);
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
147*6777b538SAndroid Build Coastguard Worker   // Currently we limit ourselves to use TraceStackFramePointers. We know that
148*6777b538SAndroid Build Coastguard Worker   // TraceStackFramePointers has an acceptable performance impact on Android.
149*6777b538SAndroid Build Coastguard Worker   base::debug::TraceStackFramePointers(&stack_trace_[0], stack_trace_.size(),
150*6777b538SAndroid Build Coastguard Worker                                        0);
151*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_LINUX)
152*6777b538SAndroid Build Coastguard Worker   // Use base::debug::CollectStackTrace as an alternative for tests on Linux. We
153*6777b538SAndroid Build Coastguard Worker   // still have a check in /base/debug/debug.gni to prevent that
154*6777b538SAndroid Build Coastguard Worker   // AllocationStackTraceRecorder is enabled accidentally on Linux.
155*6777b538SAndroid Build Coastguard Worker   base::debug::CollectStackTrace(&stack_trace_[0], stack_trace_.size());
156*6777b538SAndroid Build Coastguard Worker #else
157*6777b538SAndroid Build Coastguard Worker #error "No supported stack tracer found."
158*6777b538SAndroid Build Coastguard Worker #endif
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker struct BASE_EXPORT AllocationTraceRecorderStatistics {
162*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
163*6777b538SAndroid Build Coastguard Worker   AllocationTraceRecorderStatistics(size_t total_number_of_allocations,
164*6777b538SAndroid Build Coastguard Worker                                     size_t total_number_of_collisions);
165*6777b538SAndroid Build Coastguard Worker #else
166*6777b538SAndroid Build Coastguard Worker   AllocationTraceRecorderStatistics(size_t total_number_of_allocations);
167*6777b538SAndroid Build Coastguard Worker #endif
168*6777b538SAndroid Build Coastguard Worker 
169*6777b538SAndroid Build Coastguard Worker   // The total number of allocations that have been recorded.
170*6777b538SAndroid Build Coastguard Worker   size_t total_number_of_allocations;
171*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
172*6777b538SAndroid Build Coastguard Worker   // The total number of collisions that have been encountered. A collision
173*6777b538SAndroid Build Coastguard Worker   // happens when two threads concurrently try to record using the same slot.
174*6777b538SAndroid Build Coastguard Worker   size_t total_number_of_collisions;
175*6777b538SAndroid Build Coastguard Worker #endif
176*6777b538SAndroid Build Coastguard Worker };
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker // The recorder which holds entries for past memory operations.
179*6777b538SAndroid Build Coastguard Worker //
180*6777b538SAndroid Build Coastguard Worker // The memory image of the recorder will be copied into the crash-handler.
181*6777b538SAndroid Build Coastguard Worker // Therefore, it must not hold any references to external data which are vital
182*6777b538SAndroid Build Coastguard Worker // for proper functioning.
183*6777b538SAndroid Build Coastguard Worker //
184*6777b538SAndroid Build Coastguard Worker // It is important that the recorder itself does not allocate to prevent
185*6777b538SAndroid Build Coastguard Worker // recursive calls and save as much runtime overhead as possible.
186*6777b538SAndroid Build Coastguard Worker //
187*6777b538SAndroid Build Coastguard Worker // Therefore, records are stored in a preallocated buffer with a compile time
188*6777b538SAndroid Build Coastguard Worker // constant maximum size, see |kMaximumNumberOfMemoryOperationTraces|. Once all
189*6777b538SAndroid Build Coastguard Worker // records have been used, old records will be overwritten (fifo-style).
190*6777b538SAndroid Build Coastguard Worker //
191*6777b538SAndroid Build Coastguard Worker // The recorder works in an multithreaded environment without external locking.
192*6777b538SAndroid Build Coastguard Worker // Concurrent writes are prevented by two means:
193*6777b538SAndroid Build Coastguard Worker //  1 - We atomically increment and calculate the effective index of the record
194*6777b538SAndroid Build Coastguard Worker //  to be written.
195*6777b538SAndroid Build Coastguard Worker //  2 - If this entry is still being used (the recording thread didn't finish
196*6777b538SAndroid Build Coastguard Worker //  yet), we go back to step 1
197*6777b538SAndroid Build Coastguard Worker // Currently we do not enforce separate cache lines for each entry, which means
198*6777b538SAndroid Build Coastguard Worker // false sharing can occur. On the other hand, with 64 byte cachelines a clean
199*6777b538SAndroid Build Coastguard Worker // separation would introduce some 3*64 - sizeof(OperationRecord) = 40 bytes of
200*6777b538SAndroid Build Coastguard Worker // padding per entry.
201*6777b538SAndroid Build Coastguard Worker //
202*6777b538SAndroid Build Coastguard Worker // Note: As a process might be terminated for whatever reason while stack
203*6777b538SAndroid Build Coastguard Worker // traces are being written, the recorded data may contain some garbage.
204*6777b538SAndroid Build Coastguard Worker //
205*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/1419908): Evaluate the impact of the shared cache
206*6777b538SAndroid Build Coastguard Worker // lines between entries.
207*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT AllocationTraceRecorder {
208*6777b538SAndroid Build Coastguard Worker  public:
209*6777b538SAndroid Build Coastguard Worker   constexpr AllocationTraceRecorder() = default;
210*6777b538SAndroid Build Coastguard Worker 
211*6777b538SAndroid Build Coastguard Worker   AllocationTraceRecorder(const AllocationTraceRecorder&) = delete;
212*6777b538SAndroid Build Coastguard Worker   AllocationTraceRecorder& operator=(const AllocationTraceRecorder&) = delete;
213*6777b538SAndroid Build Coastguard Worker 
214*6777b538SAndroid Build Coastguard Worker   // The allocation event observer interface. See the dispatcher for further
215*6777b538SAndroid Build Coastguard Worker   // details. The functions are marked NO_INLINE. All other functions called but
216*6777b538SAndroid Build Coastguard Worker   // the one taking the call stack are marked ALWAYS_INLINE. This way we ensure
217*6777b538SAndroid Build Coastguard Worker   // the number of frames recorded from these functions is fixed.
218*6777b538SAndroid Build Coastguard Worker   inline void OnAllocation(
219*6777b538SAndroid Build Coastguard Worker       const base::allocator::dispatcher::AllocationNotificationData&
220*6777b538SAndroid Build Coastguard Worker           allocation_data);
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // Handle all free events.
223*6777b538SAndroid Build Coastguard Worker   inline void OnFree(
224*6777b538SAndroid Build Coastguard Worker       const base::allocator::dispatcher::FreeNotificationData& free_data);
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker   // Access functions to retrieve the current content of the recorder.
227*6777b538SAndroid Build Coastguard Worker   // Note: Since the recorder is usually updated upon each allocation or free,
228*6777b538SAndroid Build Coastguard Worker   // it is important to prevent updates if you want to read the entries at any
229*6777b538SAndroid Build Coastguard Worker   // point.
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker   // Get the current number of entries stored in the recorder. When the
232*6777b538SAndroid Build Coastguard Worker   // recorder has reached its maximum capacity, it always returns
233*6777b538SAndroid Build Coastguard Worker   // |GetMaximumNumberOfTraces()|.
234*6777b538SAndroid Build Coastguard Worker   size_t size() const;
235*6777b538SAndroid Build Coastguard Worker 
236*6777b538SAndroid Build Coastguard Worker   // Access the record of an operation by index. Oldest operation is always
237*6777b538SAndroid Build Coastguard Worker   // accessible at index 0, latest operation at |size()-1|.
238*6777b538SAndroid Build Coastguard Worker   // Note: Since a process might have crashed while a trace is being written,
239*6777b538SAndroid Build Coastguard Worker   // especially the last records might be corrupted.
240*6777b538SAndroid Build Coastguard Worker   const OperationRecord& operator[](size_t idx) const;
241*6777b538SAndroid Build Coastguard Worker 
GetMaximumNumberOfTraces()242*6777b538SAndroid Build Coastguard Worker   constexpr size_t GetMaximumNumberOfTraces() const {
243*6777b538SAndroid Build Coastguard Worker     return kMaximumNumberOfMemoryOperationTraces;
244*6777b538SAndroid Build Coastguard Worker   }
245*6777b538SAndroid Build Coastguard Worker 
246*6777b538SAndroid Build Coastguard Worker   AllocationTraceRecorderStatistics GetRecorderStatistics() const;
247*6777b538SAndroid Build Coastguard Worker 
248*6777b538SAndroid Build Coastguard Worker  private:
249*6777b538SAndroid Build Coastguard Worker   // Handle all allocation events.
250*6777b538SAndroid Build Coastguard Worker   NOINLINE void OnAllocation(const void* allocated_address,
251*6777b538SAndroid Build Coastguard Worker                              size_t allocated_size);
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker   // Handle all free events.
254*6777b538SAndroid Build Coastguard Worker   NOINLINE void OnFree(const void* freed_address);
255*6777b538SAndroid Build Coastguard Worker 
256*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE size_t GetNextIndex();
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker   ALWAYS_INLINE static constexpr size_t WrapIdxIfNeeded(size_t idx);
259*6777b538SAndroid Build Coastguard Worker 
260*6777b538SAndroid Build Coastguard Worker   // The actual container.
261*6777b538SAndroid Build Coastguard Worker   std::array<OperationRecord, kMaximumNumberOfMemoryOperationTraces>
262*6777b538SAndroid Build Coastguard Worker       alloc_trace_buffer_ = {};
263*6777b538SAndroid Build Coastguard Worker   // The total number of records that have been taken so far. Note that this
264*6777b538SAndroid Build Coastguard Worker   // might be greater than |kMaximumNumberOfMemoryOperationTraces| since we
265*6777b538SAndroid Build Coastguard Worker   // overwrite oldest items.
266*6777b538SAndroid Build Coastguard Worker   std::atomic<size_t> total_number_of_records_ = 0;
267*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
268*6777b538SAndroid Build Coastguard Worker   std::atomic<size_t> total_number_of_collisions_ = 0;
269*6777b538SAndroid Build Coastguard Worker #endif
270*6777b538SAndroid Build Coastguard Worker };
271*6777b538SAndroid Build Coastguard Worker 
OnAllocation(const base::allocator::dispatcher::AllocationNotificationData & allocation_data)272*6777b538SAndroid Build Coastguard Worker inline void AllocationTraceRecorder::OnAllocation(
273*6777b538SAndroid Build Coastguard Worker     const base::allocator::dispatcher::AllocationNotificationData&
274*6777b538SAndroid Build Coastguard Worker         allocation_data) {
275*6777b538SAndroid Build Coastguard Worker   OnAllocation(allocation_data.address(), allocation_data.size());
276*6777b538SAndroid Build Coastguard Worker }
277*6777b538SAndroid Build Coastguard Worker 
278*6777b538SAndroid Build Coastguard Worker // Handle all free events.
OnFree(const base::allocator::dispatcher::FreeNotificationData & free_data)279*6777b538SAndroid Build Coastguard Worker inline void AllocationTraceRecorder::OnFree(
280*6777b538SAndroid Build Coastguard Worker     const base::allocator::dispatcher::FreeNotificationData& free_data) {
281*6777b538SAndroid Build Coastguard Worker   OnFree(free_data.address());
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker 
WrapIdxIfNeeded(size_t idx)284*6777b538SAndroid Build Coastguard Worker ALWAYS_INLINE constexpr size_t AllocationTraceRecorder::WrapIdxIfNeeded(
285*6777b538SAndroid Build Coastguard Worker     size_t idx) {
286*6777b538SAndroid Build Coastguard Worker   // Wrapping around counter, e.g. for BUFFER_SIZE = 256, the counter will
287*6777b538SAndroid Build Coastguard Worker   // wrap around when reaching 256. To enable the compiler to emit more
288*6777b538SAndroid Build Coastguard Worker   // optimized code we assert |kMaximumNumberOfMemoryOperationTraces| is a power
289*6777b538SAndroid Build Coastguard Worker   // of two .
290*6777b538SAndroid Build Coastguard Worker   static_assert(
291*6777b538SAndroid Build Coastguard Worker       std::has_single_bit(kMaximumNumberOfMemoryOperationTraces),
292*6777b538SAndroid Build Coastguard Worker       "kMaximumNumberOfMemoryOperationTraces should be a power of 2 to "
293*6777b538SAndroid Build Coastguard Worker       "allow for fast modulo operation.");
294*6777b538SAndroid Build Coastguard Worker 
295*6777b538SAndroid Build Coastguard Worker   return idx % kMaximumNumberOfMemoryOperationTraces;
296*6777b538SAndroid Build Coastguard Worker }
297*6777b538SAndroid Build Coastguard Worker 
GetNextIndex()298*6777b538SAndroid Build Coastguard Worker ALWAYS_INLINE size_t AllocationTraceRecorder::GetNextIndex() {
299*6777b538SAndroid Build Coastguard Worker   const auto raw_idx =
300*6777b538SAndroid Build Coastguard Worker       total_number_of_records_.fetch_add(1, std::memory_order_relaxed);
301*6777b538SAndroid Build Coastguard Worker   return WrapIdxIfNeeded(raw_idx);
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker }  // namespace base::debug::tracer
305*6777b538SAndroid Build Coastguard Worker 
306*6777b538SAndroid Build Coastguard Worker #endif  // BASE_DEBUG_ALLOCATION_TRACE_H_
307