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