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 17enum AllocatorStat { 18 AllocatorStatAllocated, 19 AllocatorStatMapped, 20 AllocatorStatCount 21}; 22 23typedef uptr AllocatorStatCounters[AllocatorStatCount]; 24 25// Per-thread stats, live in per-thread cache. 26class AllocatorStats { 27 public: 28 void Init() { 29 internal_memset(this, 0, sizeof(*this)); 30 } 31 void InitLinkerInitialized() {} 32 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 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 43 void Set(AllocatorStat i, uptr v) { 44 atomic_store(&stats_[i], v, memory_order_relaxed); 45 } 46 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. 59class AllocatorGlobalStats : public AllocatorStats { 60 public: 61 void InitLinkerInitialized() { 62 next_ = this; 63 prev_ = this; 64 } 65 void Init() { 66 internal_memset(this, 0, sizeof(*this)); 67 InitLinkerInitialized(); 68 } 69 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 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 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