2016-11-08 23:04:09 +01:00
|
|
|
//===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===//
|
|
|
|
//
|
2019-08-14 10:47:11 +02:00
|
|
|
// 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
|
2016-11-08 23:04:09 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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:
|
2018-10-31 12:14:23 +01:00
|
|
|
mutable StaticSpinMutex mu_;
|
2016-11-08 23:04:09 +01:00
|
|
|
};
|
2019-08-14 10:47:11 +02:00
|
|
|
|
|
|
|
|