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