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