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