xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/scudo/standalone/stats.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===-- stats.h -------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #ifndef SCUDO_STATS_H_
100b57cec5SDimitry Andric #define SCUDO_STATS_H_
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "atomic_helpers.h"
13480093f4SDimitry Andric #include "list.h"
140b57cec5SDimitry Andric #include "mutex.h"
15*06c3fb27SDimitry Andric #include "thread_annotations.h"
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include <string.h>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace scudo {
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // Memory allocator statistics
2268d75effSDimitry Andric enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric typedef uptr StatCounters[StatCount];
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric // Per-thread stats, live in per-thread cache. We use atomics so that the
270b57cec5SDimitry Andric // numbers themselves are consistent. But we don't use atomic_{add|sub} or a
280b57cec5SDimitry Andric // lock, because those are expensive operations , and we only care for the stats
290b57cec5SDimitry Andric // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
300b57cec5SDimitry Andric // LocalStats::add'ing, this is OK, we will still get a meaningful number.
310b57cec5SDimitry Andric class LocalStats {
320b57cec5SDimitry Andric public:
init()33fe6060f1SDimitry Andric   void init() {
34fe6060f1SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
35fe6060f1SDimitry Andric       DCHECK_EQ(get(static_cast<StatType>(I)), 0U);
36fe6060f1SDimitry Andric   }
370b57cec5SDimitry Andric 
add(StatType I,uptr V)380b57cec5SDimitry Andric   void add(StatType I, uptr V) {
390b57cec5SDimitry Andric     V += atomic_load_relaxed(&StatsArray[I]);
400b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
410b57cec5SDimitry Andric   }
420b57cec5SDimitry Andric 
sub(StatType I,uptr V)430b57cec5SDimitry Andric   void sub(StatType I, uptr V) {
440b57cec5SDimitry Andric     V = atomic_load_relaxed(&StatsArray[I]) - V;
450b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
set(StatType I,uptr V)480b57cec5SDimitry Andric   void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
490b57cec5SDimitry Andric 
get(StatType I)500b57cec5SDimitry Andric   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
510b57cec5SDimitry Andric 
52fe6060f1SDimitry Andric   LocalStats *Next = nullptr;
53fe6060f1SDimitry Andric   LocalStats *Prev = nullptr;
54480093f4SDimitry Andric 
55480093f4SDimitry Andric private:
56fe6060f1SDimitry Andric   atomic_uptr StatsArray[StatCount] = {};
570b57cec5SDimitry Andric };
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
600b57cec5SDimitry Andric class GlobalStats : public LocalStats {
610b57cec5SDimitry Andric public:
init()62fe6060f1SDimitry Andric   void init() { LocalStats::init(); }
630b57cec5SDimitry Andric 
link(LocalStats * S)64*06c3fb27SDimitry Andric   void link(LocalStats *S) EXCLUDES(Mutex) {
650b57cec5SDimitry Andric     ScopedLock L(Mutex);
66480093f4SDimitry Andric     StatsList.push_back(S);
670b57cec5SDimitry Andric   }
680b57cec5SDimitry Andric 
unlink(LocalStats * S)69*06c3fb27SDimitry Andric   void unlink(LocalStats *S) EXCLUDES(Mutex) {
700b57cec5SDimitry Andric     ScopedLock L(Mutex);
71480093f4SDimitry Andric     StatsList.remove(S);
720b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
730b57cec5SDimitry Andric       add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
get(uptr * S)76*06c3fb27SDimitry Andric   void get(uptr *S) const EXCLUDES(Mutex) {
770b57cec5SDimitry Andric     ScopedLock L(Mutex);
780b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
79480093f4SDimitry Andric       S[I] = LocalStats::get(static_cast<StatType>(I));
80480093f4SDimitry Andric     for (const auto &Stats : StatsList) {
81480093f4SDimitry Andric       for (uptr I = 0; I < StatCount; I++)
82480093f4SDimitry Andric         S[I] += Stats.get(static_cast<StatType>(I));
830b57cec5SDimitry Andric     }
840b57cec5SDimitry Andric     // All stats must be non-negative.
850b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
860b57cec5SDimitry Andric       S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
lock()89*06c3fb27SDimitry Andric   void lock() ACQUIRE(Mutex) { Mutex.lock(); }
unlock()90*06c3fb27SDimitry Andric   void unlock() RELEASE(Mutex) { Mutex.unlock(); }
91fe6060f1SDimitry Andric 
disable()92*06c3fb27SDimitry Andric   void disable() ACQUIRE(Mutex) { lock(); }
enable()93*06c3fb27SDimitry Andric   void enable() RELEASE(Mutex) { unlock(); }
94480093f4SDimitry Andric 
950b57cec5SDimitry Andric private:
960b57cec5SDimitry Andric   mutable HybridMutex Mutex;
97*06c3fb27SDimitry Andric   DoublyLinkedList<LocalStats> StatsList GUARDED_BY(Mutex);
980b57cec5SDimitry Andric };
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric } // namespace scudo
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric #endif // SCUDO_STATS_H_
103