1 //===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Part of the Sanitizer Allocator. 10 // 11 //===----------------------------------------------------------------------===// 12 #ifndef SANITIZER_ALLOCATOR_H 13 #error This file must be included inside sanitizer_allocator.h 14 #endif 15 16 // Memory allocator statistics 17 enum AllocatorStat { 18 AllocatorStatAllocated, 19 AllocatorStatMapped, 20 AllocatorStatCount 21 }; 22 23 typedef uptr AllocatorStatCounters[AllocatorStatCount]; 24 25 // Per-thread stats, live in per-thread cache. 26 class AllocatorStats { 27 public: Init()28 void Init() { 29 internal_memset(this, 0, sizeof(*this)); 30 } InitLinkerInitialized()31 void InitLinkerInitialized() {} 32 Add(AllocatorStat i,uptr v)33 void Add(AllocatorStat i, uptr v) { 34 v += atomic_load(&stats_[i], memory_order_relaxed); 35 atomic_store(&stats_[i], v, memory_order_relaxed); 36 } 37 Sub(AllocatorStat i,uptr v)38 void Sub(AllocatorStat i, uptr v) { 39 v = atomic_load(&stats_[i], memory_order_relaxed) - v; 40 atomic_store(&stats_[i], v, memory_order_relaxed); 41 } 42 Set(AllocatorStat i,uptr v)43 void Set(AllocatorStat i, uptr v) { 44 atomic_store(&stats_[i], v, memory_order_relaxed); 45 } 46 Get(AllocatorStat i)47 uptr Get(AllocatorStat i) const { 48 return atomic_load(&stats_[i], memory_order_relaxed); 49 } 50 51 private: 52 friend class AllocatorGlobalStats; 53 AllocatorStats *next_; 54 AllocatorStats *prev_; 55 atomic_uintptr_t stats_[AllocatorStatCount]; 56 }; 57 58 // Global stats, used for aggregation and querying. 59 class AllocatorGlobalStats : public AllocatorStats { 60 public: InitLinkerInitialized()61 void InitLinkerInitialized() { 62 next_ = this; 63 prev_ = this; 64 } Init()65 void Init() { 66 internal_memset(this, 0, sizeof(*this)); 67 InitLinkerInitialized(); 68 } 69 Register(AllocatorStats * s)70 void Register(AllocatorStats *s) { 71 SpinMutexLock l(&mu_); 72 s->next_ = next_; 73 s->prev_ = this; 74 next_->prev_ = s; 75 next_ = s; 76 } 77 Unregister(AllocatorStats * s)78 void Unregister(AllocatorStats *s) { 79 SpinMutexLock l(&mu_); 80 s->prev_->next_ = s->next_; 81 s->next_->prev_ = s->prev_; 82 for (int i = 0; i < AllocatorStatCount; i++) 83 Add(AllocatorStat(i), s->Get(AllocatorStat(i))); 84 } 85 Get(AllocatorStatCounters s)86 void Get(AllocatorStatCounters s) const { 87 internal_memset(s, 0, AllocatorStatCount * sizeof(uptr)); 88 SpinMutexLock l(&mu_); 89 const AllocatorStats *stats = this; 90 for (;;) { 91 for (int i = 0; i < AllocatorStatCount; i++) 92 s[i] += stats->Get(AllocatorStat(i)); 93 stats = stats->next_; 94 if (stats == this) 95 break; 96 } 97 // All stats must be non-negative. 98 for (int i = 0; i < AllocatorStatCount; i++) 99 s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0; 100 } 101 102 private: 103 mutable StaticSpinMutex mu_; 104 }; 105 106 107