190075Sobrien//===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===// 2169706Skan// 390075Sobrien// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 490075Sobrien// See https://llvm.org/LICENSE.txt for license information. 5132742Skan// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 690075Sobrien// 7132742Skan//===----------------------------------------------------------------------===// 890075Sobrien// 990075Sobrien// Part of the Sanitizer Allocator. 1090075Sobrien// 1190075Sobrien//===----------------------------------------------------------------------===// 12132742Skan#ifndef SANITIZER_ALLOCATOR_H 1390075Sobrien#error This file must be included inside sanitizer_allocator.h 1490075Sobrien#endif 1590075Sobrien 1690075Sobrien// Memory allocator statistics 1790075Sobrienenum AllocatorStat { 18132742Skan AllocatorStatAllocated, 19169706Skan AllocatorStatMapped, 20169706Skan AllocatorStatCount 2190075Sobrien}; 2298599Sobrien 2390075Sobrientypedef uptr AllocatorStatCounters[AllocatorStatCount]; 2498599Sobrien 25117417Skan// Per-thread stats, live in per-thread cache. 2690075Sobrienclass AllocatorStats { 2790075Sobrien public: 28123546Sobrien void Init() { 29123546Sobrien internal_memset(this, 0, sizeof(*this)); 30123546Sobrien } 31123546Sobrien void InitLinkerInitialized() {} 32123561Sobrien 33123561Sobrien void Add(AllocatorStat i, uptr v) { 34123561Sobrien v += atomic_load(&stats_[i], memory_order_relaxed); 35123561Sobrien atomic_store(&stats_[i], v, memory_order_relaxed); 36123546Sobrien } 37123546Sobrien 38123546Sobrien void Sub(AllocatorStat i, uptr v) { 39132742Skan v = atomic_load(&stats_[i], memory_order_relaxed) - v; 40132742Skan atomic_store(&stats_[i], v, memory_order_relaxed); 41132742Skan } 4290075Sobrien 4390075Sobrien void Set(AllocatorStat i, uptr v) { 4490075Sobrien atomic_store(&stats_[i], v, memory_order_relaxed); 4590075Sobrien } 4690075Sobrien 4790075Sobrien uptr Get(AllocatorStat i) const { 48132742Skan return atomic_load(&stats_[i], memory_order_relaxed); 4990075Sobrien } 5090075Sobrien 5190075Sobrien private: 5290075Sobrien friend class AllocatorGlobalStats; 5390075Sobrien AllocatorStats *next_; 5490075Sobrien AllocatorStats *prev_; 55132742Skan atomic_uintptr_t stats_[AllocatorStatCount]; 5690075Sobrien}; 5790075Sobrien 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