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