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() { internal_memset(this, 0, sizeof(*this)); } Add(AllocatorStat i,uptr v)29 void Add(AllocatorStat i, uptr v) { 30 atomic_fetch_add(&stats_[i], v, memory_order_relaxed); 31 } 32 Sub(AllocatorStat i,uptr v)33 void Sub(AllocatorStat i, uptr v) { 34 atomic_fetch_sub(&stats_[i], v, memory_order_relaxed); 35 } 36 Set(AllocatorStat i,uptr v)37 void Set(AllocatorStat i, uptr v) { 38 atomic_store(&stats_[i], v, memory_order_relaxed); 39 } 40 Get(AllocatorStat i)41 uptr Get(AllocatorStat i) const { 42 return atomic_load(&stats_[i], memory_order_relaxed); 43 } 44 45 private: 46 friend class AllocatorGlobalStats; 47 AllocatorStats *next_; 48 AllocatorStats *prev_; 49 atomic_uintptr_t stats_[AllocatorStatCount]; 50 }; 51 52 // Global stats, used for aggregation and querying. 53 class AllocatorGlobalStats : public AllocatorStats { 54 public: Init()55 void Init() { 56 internal_memset(this, 0, sizeof(*this)); 57 } 58 Register(AllocatorStats * s)59 void Register(AllocatorStats *s) { 60 SpinMutexLock l(&mu_); 61 LazyInit(); 62 s->next_ = next_; 63 s->prev_ = this; 64 next_->prev_ = s; 65 next_ = s; 66 } 67 Unregister(AllocatorStats * s)68 void Unregister(AllocatorStats *s) { 69 SpinMutexLock l(&mu_); 70 s->prev_->next_ = s->next_; 71 s->next_->prev_ = s->prev_; 72 for (int i = 0; i < AllocatorStatCount; i++) 73 Add(AllocatorStat(i), s->Get(AllocatorStat(i))); 74 } 75 Get(AllocatorStatCounters s)76 void Get(AllocatorStatCounters s) const { 77 internal_memset(s, 0, AllocatorStatCount * sizeof(uptr)); 78 SpinMutexLock l(&mu_); 79 const AllocatorStats *stats = this; 80 for (; stats;) { 81 for (int i = 0; i < AllocatorStatCount; i++) 82 s[i] += stats->Get(AllocatorStat(i)); 83 stats = stats->next_; 84 if (stats == this) 85 break; 86 } 87 // All stats must be non-negative. 88 for (int i = 0; i < AllocatorStatCount; i++) 89 s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0; 90 } 91 92 private: LazyInit()93 void LazyInit() { 94 if (!next_) { 95 next_ = this; 96 prev_ = this; 97 } 98 } 99 100 mutable StaticSpinMutex mu_; 101 }; 102 103 104