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