• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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