xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/stats.h (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- stats.h -------------------------------------------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #ifndef SCUDO_STATS_H_
10*0b57cec5SDimitry Andric #define SCUDO_STATS_H_
11*0b57cec5SDimitry Andric 
12*0b57cec5SDimitry Andric #include "atomic_helpers.h"
13*0b57cec5SDimitry Andric #include "mutex.h"
14*0b57cec5SDimitry Andric 
15*0b57cec5SDimitry Andric #include <string.h>
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric namespace scudo {
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric // Memory allocator statistics
20*0b57cec5SDimitry Andric enum StatType { StatAllocated, StatMapped, StatCount };
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric typedef uptr StatCounters[StatCount];
23*0b57cec5SDimitry Andric 
24*0b57cec5SDimitry Andric // Per-thread stats, live in per-thread cache. We use atomics so that the
25*0b57cec5SDimitry Andric // numbers themselves are consistent. But we don't use atomic_{add|sub} or a
26*0b57cec5SDimitry Andric // lock, because those are expensive operations , and we only care for the stats
27*0b57cec5SDimitry Andric // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
28*0b57cec5SDimitry Andric // LocalStats::add'ing, this is OK, we will still get a meaningful number.
29*0b57cec5SDimitry Andric class LocalStats {
30*0b57cec5SDimitry Andric public:
31*0b57cec5SDimitry Andric   void initLinkerInitialized() {}
32*0b57cec5SDimitry Andric   void init() { memset(this, 0, sizeof(*this)); }
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric   void add(StatType I, uptr V) {
35*0b57cec5SDimitry Andric     V += atomic_load_relaxed(&StatsArray[I]);
36*0b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
37*0b57cec5SDimitry Andric   }
38*0b57cec5SDimitry Andric 
39*0b57cec5SDimitry Andric   void sub(StatType I, uptr V) {
40*0b57cec5SDimitry Andric     V = atomic_load_relaxed(&StatsArray[I]) - V;
41*0b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
42*0b57cec5SDimitry Andric   }
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric   void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
47*0b57cec5SDimitry Andric 
48*0b57cec5SDimitry Andric private:
49*0b57cec5SDimitry Andric   friend class GlobalStats;
50*0b57cec5SDimitry Andric   atomic_uptr StatsArray[StatCount];
51*0b57cec5SDimitry Andric   LocalStats *Next;
52*0b57cec5SDimitry Andric   LocalStats *Prev;
53*0b57cec5SDimitry Andric };
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
56*0b57cec5SDimitry Andric class GlobalStats : public LocalStats {
57*0b57cec5SDimitry Andric public:
58*0b57cec5SDimitry Andric   void initLinkerInitialized() {
59*0b57cec5SDimitry Andric     Next = this;
60*0b57cec5SDimitry Andric     Prev = this;
61*0b57cec5SDimitry Andric   }
62*0b57cec5SDimitry Andric   void init() {
63*0b57cec5SDimitry Andric     memset(this, 0, sizeof(*this));
64*0b57cec5SDimitry Andric     initLinkerInitialized();
65*0b57cec5SDimitry Andric   }
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric   void link(LocalStats *S) {
68*0b57cec5SDimitry Andric     ScopedLock L(Mutex);
69*0b57cec5SDimitry Andric     S->Next = Next;
70*0b57cec5SDimitry Andric     S->Prev = this;
71*0b57cec5SDimitry Andric     Next->Prev = S;
72*0b57cec5SDimitry Andric     Next = S;
73*0b57cec5SDimitry Andric   }
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric   void unlink(LocalStats *S) {
76*0b57cec5SDimitry Andric     ScopedLock L(Mutex);
77*0b57cec5SDimitry Andric     S->Prev->Next = S->Next;
78*0b57cec5SDimitry Andric     S->Next->Prev = S->Prev;
79*0b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
80*0b57cec5SDimitry Andric       add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
81*0b57cec5SDimitry Andric   }
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric   void get(uptr *S) const {
84*0b57cec5SDimitry Andric     memset(S, 0, StatCount * sizeof(uptr));
85*0b57cec5SDimitry Andric     ScopedLock L(Mutex);
86*0b57cec5SDimitry Andric     const LocalStats *Stats = this;
87*0b57cec5SDimitry Andric     for (;;) {
88*0b57cec5SDimitry Andric       for (uptr I = 0; I < StatCount; I++)
89*0b57cec5SDimitry Andric         S[I] += Stats->get(static_cast<StatType>(I));
90*0b57cec5SDimitry Andric       Stats = Stats->Next;
91*0b57cec5SDimitry Andric       if (Stats == this)
92*0b57cec5SDimitry Andric         break;
93*0b57cec5SDimitry Andric     }
94*0b57cec5SDimitry Andric     // All stats must be non-negative.
95*0b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
96*0b57cec5SDimitry Andric       S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
97*0b57cec5SDimitry Andric   }
98*0b57cec5SDimitry Andric 
99*0b57cec5SDimitry Andric private:
100*0b57cec5SDimitry Andric   mutable HybridMutex Mutex;
101*0b57cec5SDimitry Andric };
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric } // namespace scudo
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric #endif // SCUDO_STATS_H_
106