blob: d76b904949ea2164c8931eb35532f0fd8118acf1 [file] [log] [blame]
Dynamic Tools Team517193e2019-09-11 14:48:41 +00001//===-- 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"
Dynamic Tools Team35997702019-10-28 15:06:10 -070013#include "list.h"
Dynamic Tools Team517193e2019-09-11 14:48:41 +000014#include "mutex.h"
15
16#include <string.h>
17
18namespace scudo {
19
20// Memory allocator statistics
21enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
22
23typedef 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.
30class LocalStats {
31public:
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
Dynamic Tools Team517193e2019-09-11 14:48:41 +000049 LocalStats *Next;
50 LocalStats *Prev;
Dynamic Tools Team35997702019-10-28 15:06:10 -070051
52private:
53 atomic_uptr StatsArray[StatCount];
Dynamic Tools Team517193e2019-09-11 14:48:41 +000054};
55
56// Global stats, used for aggregation and querying.
57class GlobalStats : public LocalStats {
58public:
Dynamic Tools Team35997702019-10-28 15:06:10 -070059 void initLinkerInitialized() {}
Dynamic Tools Team517193e2019-09-11 14:48:41 +000060 void init() {
Dynamic Tools Team08b690a2020-04-10 13:41:12 -070061 LocalStats::init();
62 Mutex.init();
63 StatsList = {};
Dynamic Tools Team517193e2019-09-11 14:48:41 +000064 initLinkerInitialized();
65 }
66
67 void link(LocalStats *S) {
68 ScopedLock L(Mutex);
Dynamic Tools Team35997702019-10-28 15:06:10 -070069 StatsList.push_back(S);
Dynamic Tools Team517193e2019-09-11 14:48:41 +000070 }
71
72 void unlink(LocalStats *S) {
73 ScopedLock L(Mutex);
Dynamic Tools Team35997702019-10-28 15:06:10 -070074 StatsList.remove(S);
Dynamic Tools Team517193e2019-09-11 14:48:41 +000075 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 {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000080 ScopedLock L(Mutex);
Dynamic Tools Team35997702019-10-28 15:06:10 -070081 for (uptr I = 0; I < StatCount; I++)
82 S[I] = LocalStats::get(static_cast<StatType>(I));
83 for (const auto &Stats : StatsList) {
Dynamic Tools Team517193e2019-09-11 14:48:41 +000084 for (uptr I = 0; I < StatCount; I++)
Dynamic Tools Team35997702019-10-28 15:06:10 -070085 S[I] += Stats.get(static_cast<StatType>(I));
Dynamic Tools Team517193e2019-09-11 14:48:41 +000086 }
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
Dynamic Tools Team83eaa512020-01-09 11:43:16 -080092 void disable() { Mutex.lock(); }
93 void enable() { Mutex.unlock(); }
94
Dynamic Tools Team517193e2019-09-11 14:48:41 +000095private:
96 mutable HybridMutex Mutex;
Dynamic Tools Team35997702019-10-28 15:06:10 -070097 DoublyLinkedList<LocalStats> StatsList;
Dynamic Tools Team517193e2019-09-11 14:48:41 +000098};
99
100} // namespace scudo
101
102#endif // SCUDO_STATS_H_