116d9a3a4SKostya Kortchinsky //===-- stats.h -------------------------------------------------*- C++ -*-===// 216d9a3a4SKostya Kortchinsky // 316d9a3a4SKostya Kortchinsky // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 416d9a3a4SKostya Kortchinsky // See https://llvm.org/LICENSE.txt for license information. 516d9a3a4SKostya Kortchinsky // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 616d9a3a4SKostya Kortchinsky // 716d9a3a4SKostya Kortchinsky //===----------------------------------------------------------------------===// 816d9a3a4SKostya Kortchinsky 916d9a3a4SKostya Kortchinsky #ifndef SCUDO_STATS_H_ 1016d9a3a4SKostya Kortchinsky #define SCUDO_STATS_H_ 1116d9a3a4SKostya Kortchinsky 1216d9a3a4SKostya Kortchinsky #include "atomic_helpers.h" 136f2de9cbSKostya Kortchinsky #include "list.h" 1416d9a3a4SKostya Kortchinsky #include "mutex.h" 15*6a4c3959SChia-hung Duan #include "thread_annotations.h" 1616d9a3a4SKostya Kortchinsky 1716d9a3a4SKostya Kortchinsky #include <string.h> 1816d9a3a4SKostya Kortchinsky 1916d9a3a4SKostya Kortchinsky namespace scudo { 2016d9a3a4SKostya Kortchinsky 2116d9a3a4SKostya Kortchinsky // Memory allocator statistics 222be59170SKostya Kortchinsky enum StatType { StatAllocated, StatFree, StatMapped, StatCount }; 2316d9a3a4SKostya Kortchinsky 2416d9a3a4SKostya Kortchinsky typedef uptr StatCounters[StatCount]; 2516d9a3a4SKostya Kortchinsky 2616d9a3a4SKostya Kortchinsky // Per-thread stats, live in per-thread cache. We use atomics so that the 2716d9a3a4SKostya Kortchinsky // numbers themselves are consistent. But we don't use atomic_{add|sub} or a 2816d9a3a4SKostya Kortchinsky // lock, because those are expensive operations , and we only care for the stats 2916d9a3a4SKostya Kortchinsky // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is 3016d9a3a4SKostya Kortchinsky // LocalStats::add'ing, this is OK, we will still get a meaningful number. 3116d9a3a4SKostya Kortchinsky class LocalStats { 3216d9a3a4SKostya Kortchinsky public: init()33a45877eeSKostya Kortchinsky void init() { 34a45877eeSKostya Kortchinsky for (uptr I = 0; I < StatCount; I++) 35a45877eeSKostya Kortchinsky DCHECK_EQ(get(static_cast<StatType>(I)), 0U); 36a45877eeSKostya Kortchinsky } 3716d9a3a4SKostya Kortchinsky add(StatType I,uptr V)3816d9a3a4SKostya Kortchinsky void add(StatType I, uptr V) { 3916d9a3a4SKostya Kortchinsky V += atomic_load_relaxed(&StatsArray[I]); 4016d9a3a4SKostya Kortchinsky atomic_store_relaxed(&StatsArray[I], V); 4116d9a3a4SKostya Kortchinsky } 4216d9a3a4SKostya Kortchinsky sub(StatType I,uptr V)4316d9a3a4SKostya Kortchinsky void sub(StatType I, uptr V) { 4416d9a3a4SKostya Kortchinsky V = atomic_load_relaxed(&StatsArray[I]) - V; 4516d9a3a4SKostya Kortchinsky atomic_store_relaxed(&StatsArray[I], V); 4616d9a3a4SKostya Kortchinsky } 4716d9a3a4SKostya Kortchinsky set(StatType I,uptr V)4816d9a3a4SKostya Kortchinsky void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); } 4916d9a3a4SKostya Kortchinsky get(StatType I)5016d9a3a4SKostya Kortchinsky uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); } 5116d9a3a4SKostya Kortchinsky 52d56ef852SVitaly Buka LocalStats *Next = nullptr; 53d56ef852SVitaly Buka LocalStats *Prev = nullptr; 546f2de9cbSKostya Kortchinsky 556f2de9cbSKostya Kortchinsky private: 56d56ef852SVitaly Buka atomic_uptr StatsArray[StatCount] = {}; 5716d9a3a4SKostya Kortchinsky }; 5816d9a3a4SKostya Kortchinsky 5916d9a3a4SKostya Kortchinsky // Global stats, used for aggregation and querying. 6016d9a3a4SKostya Kortchinsky class GlobalStats : public LocalStats { 6116d9a3a4SKostya Kortchinsky public: init()62a45877eeSKostya Kortchinsky void init() { LocalStats::init(); } 6316d9a3a4SKostya Kortchinsky link(LocalStats * S)64*6a4c3959SChia-hung Duan void link(LocalStats *S) EXCLUDES(Mutex) { 65aeb38262SKostya Kortchinsky ScopedLock L(Mutex); 666f2de9cbSKostya Kortchinsky StatsList.push_back(S); 6716d9a3a4SKostya Kortchinsky } 6816d9a3a4SKostya Kortchinsky unlink(LocalStats * S)69*6a4c3959SChia-hung Duan void unlink(LocalStats *S) EXCLUDES(Mutex) { 70aeb38262SKostya Kortchinsky ScopedLock L(Mutex); 716f2de9cbSKostya Kortchinsky StatsList.remove(S); 7216d9a3a4SKostya Kortchinsky for (uptr I = 0; I < StatCount; I++) 7316d9a3a4SKostya Kortchinsky add(static_cast<StatType>(I), S->get(static_cast<StatType>(I))); 7416d9a3a4SKostya Kortchinsky } 7516d9a3a4SKostya Kortchinsky get(uptr * S)76*6a4c3959SChia-hung Duan void get(uptr *S) const EXCLUDES(Mutex) { 77aeb38262SKostya Kortchinsky ScopedLock L(Mutex); 7816d9a3a4SKostya Kortchinsky for (uptr I = 0; I < StatCount; I++) 796f2de9cbSKostya Kortchinsky S[I] = LocalStats::get(static_cast<StatType>(I)); 806f2de9cbSKostya Kortchinsky for (const auto &Stats : StatsList) { 816f2de9cbSKostya Kortchinsky for (uptr I = 0; I < StatCount; I++) 826f2de9cbSKostya Kortchinsky S[I] += Stats.get(static_cast<StatType>(I)); 8316d9a3a4SKostya Kortchinsky } 8416d9a3a4SKostya Kortchinsky // All stats must be non-negative. 8516d9a3a4SKostya Kortchinsky for (uptr I = 0; I < StatCount; I++) 8616d9a3a4SKostya Kortchinsky S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0; 8716d9a3a4SKostya Kortchinsky } 8816d9a3a4SKostya Kortchinsky lock()89*6a4c3959SChia-hung Duan void lock() ACQUIRE(Mutex) { Mutex.lock(); } unlock()90*6a4c3959SChia-hung Duan void unlock() RELEASE(Mutex) { Mutex.unlock(); } 91e78b64dfSMitch Phillips disable()92*6a4c3959SChia-hung Duan void disable() ACQUIRE(Mutex) { lock(); } enable()93*6a4c3959SChia-hung Duan void enable() RELEASE(Mutex) { unlock(); } 949ef6faf4SKostya Kortchinsky 9516d9a3a4SKostya Kortchinsky private: 96aeb38262SKostya Kortchinsky mutable HybridMutex Mutex; 97*6a4c3959SChia-hung Duan DoublyLinkedList<LocalStats> StatsList GUARDED_BY(Mutex); 9816d9a3a4SKostya Kortchinsky }; 9916d9a3a4SKostya Kortchinsky 10016d9a3a4SKostya Kortchinsky } // namespace scudo 10116d9a3a4SKostya Kortchinsky 10216d9a3a4SKostya Kortchinsky #endif // SCUDO_STATS_H_ 103