1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/debug/allocation_trace.h"
6
7 #include <array>
8 #include <atomic>
9
10 #include "base/check_op.h"
11
12 namespace base::debug::tracer {
13
IsRecording() const14 bool OperationRecord::IsRecording() const {
15 if (is_recording_.test_and_set()) {
16 return true;
17 }
18
19 is_recording_.clear();
20 return false;
21 }
22
GetOperationType() const23 OperationType OperationRecord::GetOperationType() const {
24 return operation_type_;
25 }
26
GetAddress() const27 const void* OperationRecord::GetAddress() const {
28 return address_;
29 }
30
GetSize() const31 size_t OperationRecord::GetSize() const {
32 return size_;
33 }
34
GetStackTrace() const35 const StackTraceContainer& OperationRecord::GetStackTrace() const {
36 return stack_trace_;
37 }
38
39 #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
AllocationTraceRecorderStatistics(size_t total_number_of_allocations,size_t total_number_of_collisions)40 AllocationTraceRecorderStatistics::AllocationTraceRecorderStatistics(
41 size_t total_number_of_allocations,
42 size_t total_number_of_collisions)
43 : total_number_of_allocations(total_number_of_allocations),
44 total_number_of_collisions(total_number_of_collisions) {}
45 #else
AllocationTraceRecorderStatistics(size_t total_number_of_allocations)46 AllocationTraceRecorderStatistics::AllocationTraceRecorderStatistics(
47 size_t total_number_of_allocations)
48 : total_number_of_allocations(total_number_of_allocations) {}
49 #endif
50
OnAllocation(const void * allocated_address,size_t allocated_size,base::allocator::dispatcher::AllocationSubsystem subsystem,const char * type)51 void AllocationTraceRecorder::OnAllocation(
52 const void* allocated_address,
53 size_t allocated_size,
54 base::allocator::dispatcher::AllocationSubsystem subsystem,
55 const char* type) {
56 // Record the allocation into the next available slot, allowing for failure
57 // due to the slot already being in-use by another
58 // OperationRecord::Initialize*() call from another thread.
59 for (auto index = GetNextIndex();
60 !alloc_trace_buffer_[index].InitializeAllocation(allocated_address,
61 allocated_size);
62 index = GetNextIndex()) {
63 #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
64 total_number_of_collisions_.fetch_add(1, std::memory_order_relaxed);
65 #endif
66 }
67 }
68
OnFree(const void * freed_address)69 void AllocationTraceRecorder::OnFree(const void* freed_address) {
70 // Record the free into the next available slot, allowing for failure due to
71 // the slot already being in-use by another OperationRecord::Initialize*()
72 // call from another thread.
73 for (auto index = GetNextIndex();
74 !alloc_trace_buffer_[index].InitializeFree(freed_address);
75 index = GetNextIndex()) {
76 #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
77 total_number_of_collisions_.fetch_add(1, std::memory_order_relaxed);
78 #endif
79 }
80 }
81
size() const82 size_t AllocationTraceRecorder::size() const {
83 return std::min(kMaximumNumberOfMemoryOperationTraces,
84 total_number_of_records_.load(std::memory_order_relaxed));
85 }
86
operator [](size_t idx) const87 const OperationRecord& AllocationTraceRecorder::operator[](size_t idx) const {
88 DCHECK_LT(idx, size());
89
90 const size_t array_index =
91 size() < GetMaximumNumberOfTraces()
92 ? idx
93 : WrapIdxIfNeeded(
94 total_number_of_records_.load(std::memory_order_relaxed) + idx);
95
96 DCHECK_LT(array_index, alloc_trace_buffer_.size());
97
98 return alloc_trace_buffer_[array_index];
99 }
100
101 AllocationTraceRecorderStatistics
GetRecorderStatistics() const102 AllocationTraceRecorder::GetRecorderStatistics() const {
103 #if BUILDFLAG(ENABLE_ALLOCATION_TRACE_RECORDER_FULL_REPORTING)
104 return {total_number_of_records_.load(std::memory_order_relaxed),
105 total_number_of_collisions_.load(std::memory_order_relaxed)};
106 #else
107 return {total_number_of_records_.load(std::memory_order_relaxed)};
108 #endif
109 }
110
111 } // namespace base::debug::tracer