1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
//===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Part of the Sanitizer Allocator.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_ALLOCATOR_H
#error This file must be included inside sanitizer_allocator.h
#endif
// Memory allocator statistics
enum AllocatorStat {
AllocatorStatAllocated,
AllocatorStatMapped,
AllocatorStatCount
};
typedef uptr AllocatorStatCounters[AllocatorStatCount];
// Per-thread stats, live in per-thread cache.
class AllocatorStats {
public:
void Init() {
internal_memset(this, 0, sizeof(*this));
}
void InitLinkerInitialized() {}
void Add(AllocatorStat i, uptr v) {
v += atomic_load(&stats_[i], memory_order_relaxed);
atomic_store(&stats_[i], v, memory_order_relaxed);
}
void Sub(AllocatorStat i, uptr v) {
v = atomic_load(&stats_[i], memory_order_relaxed) - v;
atomic_store(&stats_[i], v, memory_order_relaxed);
}
void Set(AllocatorStat i, uptr v) {
atomic_store(&stats_[i], v, memory_order_relaxed);
}
uptr Get(AllocatorStat i) const {
return atomic_load(&stats_[i], memory_order_relaxed);
}
private:
friend class AllocatorGlobalStats;
AllocatorStats *next_;
AllocatorStats *prev_;
atomic_uintptr_t stats_[AllocatorStatCount];
};
// Global stats, used for aggregation and querying.
class AllocatorGlobalStats : public AllocatorStats {
public:
void InitLinkerInitialized() {
next_ = this;
prev_ = this;
}
void Init() {
internal_memset(this, 0, sizeof(*this));
InitLinkerInitialized();
}
void Register(AllocatorStats *s) {
SpinMutexLock l(&mu_);
s->next_ = next_;
s->prev_ = this;
next_->prev_ = s;
next_ = s;
}
void Unregister(AllocatorStats *s) {
SpinMutexLock l(&mu_);
s->prev_->next_ = s->next_;
s->next_->prev_ = s->prev_;
for (int i = 0; i < AllocatorStatCount; i++)
Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
}
void Get(AllocatorStatCounters s) const {
internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
SpinMutexLock l(&mu_);
const AllocatorStats *stats = this;
for (;;) {
for (int i = 0; i < AllocatorStatCount; i++)
s[i] += stats->Get(AllocatorStat(i));
stats = stats->next_;
if (stats == this)
break;
}
// All stats must be non-negative.
for (int i = 0; i < AllocatorStatCount; i++)
s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
}
private:
mutable StaticSpinMutex mu_;
};
|