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