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