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