13cab2bb3Spatrick //===-- stats.h -------------------------------------------------*- C++ -*-===// 23cab2bb3Spatrick // 33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information. 53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63cab2bb3Spatrick // 73cab2bb3Spatrick //===----------------------------------------------------------------------===// 83cab2bb3Spatrick 93cab2bb3Spatrick #ifndef SCUDO_STATS_H_ 103cab2bb3Spatrick #define SCUDO_STATS_H_ 113cab2bb3Spatrick 123cab2bb3Spatrick #include "atomic_helpers.h" 133cab2bb3Spatrick #include "list.h" 143cab2bb3Spatrick #include "mutex.h" 153cab2bb3Spatrick 163cab2bb3Spatrick #include <string.h> 173cab2bb3Spatrick 183cab2bb3Spatrick namespace scudo { 193cab2bb3Spatrick 203cab2bb3Spatrick // Memory allocator statistics 213cab2bb3Spatrick enum StatType { StatAllocated, StatFree, StatMapped, StatCount }; 223cab2bb3Spatrick 233cab2bb3Spatrick typedef uptr StatCounters[StatCount]; 243cab2bb3Spatrick 253cab2bb3Spatrick // Per-thread stats, live in per-thread cache. We use atomics so that the 263cab2bb3Spatrick // numbers themselves are consistent. But we don't use atomic_{add|sub} or a 273cab2bb3Spatrick // lock, because those are expensive operations , and we only care for the stats 283cab2bb3Spatrick // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is 293cab2bb3Spatrick // LocalStats::add'ing, this is OK, we will still get a meaningful number. 303cab2bb3Spatrick class LocalStats { 313cab2bb3Spatrick public: init()32*d89ec533Spatrick void init() { 33*d89ec533Spatrick for (uptr I = 0; I < StatCount; I++) 34*d89ec533Spatrick DCHECK_EQ(get(static_cast<StatType>(I)), 0U); 35*d89ec533Spatrick } 363cab2bb3Spatrick add(StatType I,uptr V)373cab2bb3Spatrick void add(StatType I, uptr V) { 383cab2bb3Spatrick V += atomic_load_relaxed(&StatsArray[I]); 393cab2bb3Spatrick atomic_store_relaxed(&StatsArray[I], V); 403cab2bb3Spatrick } 413cab2bb3Spatrick sub(StatType I,uptr V)423cab2bb3Spatrick void sub(StatType I, uptr V) { 433cab2bb3Spatrick V = atomic_load_relaxed(&StatsArray[I]) - V; 443cab2bb3Spatrick atomic_store_relaxed(&StatsArray[I], V); 453cab2bb3Spatrick } 463cab2bb3Spatrick set(StatType I,uptr V)473cab2bb3Spatrick void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); } 483cab2bb3Spatrick get(StatType I)493cab2bb3Spatrick uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); } 503cab2bb3Spatrick 51*d89ec533Spatrick LocalStats *Next = nullptr; 52*d89ec533Spatrick LocalStats *Prev = nullptr; 533cab2bb3Spatrick 543cab2bb3Spatrick private: 55*d89ec533Spatrick atomic_uptr StatsArray[StatCount] = {}; 563cab2bb3Spatrick }; 573cab2bb3Spatrick 583cab2bb3Spatrick // Global stats, used for aggregation and querying. 593cab2bb3Spatrick class GlobalStats : public LocalStats { 603cab2bb3Spatrick public: init()61*d89ec533Spatrick void init() { LocalStats::init(); } 623cab2bb3Spatrick link(LocalStats * S)633cab2bb3Spatrick void link(LocalStats *S) { 643cab2bb3Spatrick ScopedLock L(Mutex); 653cab2bb3Spatrick StatsList.push_back(S); 663cab2bb3Spatrick } 673cab2bb3Spatrick unlink(LocalStats * S)683cab2bb3Spatrick void unlink(LocalStats *S) { 693cab2bb3Spatrick ScopedLock L(Mutex); 703cab2bb3Spatrick StatsList.remove(S); 713cab2bb3Spatrick for (uptr I = 0; I < StatCount; I++) 723cab2bb3Spatrick add(static_cast<StatType>(I), S->get(static_cast<StatType>(I))); 733cab2bb3Spatrick } 743cab2bb3Spatrick get(uptr * S)753cab2bb3Spatrick void get(uptr *S) const { 763cab2bb3Spatrick ScopedLock L(Mutex); 773cab2bb3Spatrick for (uptr I = 0; I < StatCount; I++) 783cab2bb3Spatrick S[I] = LocalStats::get(static_cast<StatType>(I)); 793cab2bb3Spatrick for (const auto &Stats : StatsList) { 803cab2bb3Spatrick for (uptr I = 0; I < StatCount; I++) 813cab2bb3Spatrick S[I] += Stats.get(static_cast<StatType>(I)); 823cab2bb3Spatrick } 833cab2bb3Spatrick // All stats must be non-negative. 843cab2bb3Spatrick for (uptr I = 0; I < StatCount; I++) 853cab2bb3Spatrick S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0; 863cab2bb3Spatrick } 873cab2bb3Spatrick lock()88*d89ec533Spatrick void lock() { Mutex.lock(); } unlock()89*d89ec533Spatrick void unlock() { Mutex.unlock(); } 90*d89ec533Spatrick disable()91*d89ec533Spatrick void disable() { lock(); } enable()92*d89ec533Spatrick void enable() { unlock(); } 933cab2bb3Spatrick 943cab2bb3Spatrick private: 953cab2bb3Spatrick mutable HybridMutex Mutex; 963cab2bb3Spatrick DoublyLinkedList<LocalStats> StatsList; 973cab2bb3Spatrick }; 983cab2bb3Spatrick 993cab2bb3Spatrick } // namespace scudo 1003cab2bb3Spatrick 1013cab2bb3Spatrick #endif // SCUDO_STATS_H_ 102