xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/stats.h (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include <string.h>
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace scudo {
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric // Memory allocator statistics
2168d75effSDimitry Andric enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric typedef uptr StatCounters[StatCount];
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric // Per-thread stats, live in per-thread cache. We use atomics so that the
260b57cec5SDimitry Andric // numbers themselves are consistent. But we don't use atomic_{add|sub} or a
270b57cec5SDimitry Andric // lock, because those are expensive operations , and we only care for the stats
280b57cec5SDimitry Andric // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
290b57cec5SDimitry Andric // LocalStats::add'ing, this is OK, we will still get a meaningful number.
300b57cec5SDimitry Andric class LocalStats {
310b57cec5SDimitry Andric public:
32*fe6060f1SDimitry Andric   void init() {
33*fe6060f1SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
34*fe6060f1SDimitry Andric       DCHECK_EQ(get(static_cast<StatType>(I)), 0U);
35*fe6060f1SDimitry Andric   }
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   void add(StatType I, uptr V) {
380b57cec5SDimitry Andric     V += atomic_load_relaxed(&StatsArray[I]);
390b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   void sub(StatType I, uptr V) {
430b57cec5SDimitry Andric     V = atomic_load_relaxed(&StatsArray[I]) - V;
440b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
450b57cec5SDimitry Andric   }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
500b57cec5SDimitry Andric 
51*fe6060f1SDimitry Andric   LocalStats *Next = nullptr;
52*fe6060f1SDimitry Andric   LocalStats *Prev = nullptr;
53480093f4SDimitry Andric 
54480093f4SDimitry Andric private:
55*fe6060f1SDimitry Andric   atomic_uptr StatsArray[StatCount] = {};
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
590b57cec5SDimitry Andric class GlobalStats : public LocalStats {
600b57cec5SDimitry Andric public:
61*fe6060f1SDimitry Andric   void init() { LocalStats::init(); }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   void link(LocalStats *S) {
640b57cec5SDimitry Andric     ScopedLock L(Mutex);
65480093f4SDimitry Andric     StatsList.push_back(S);
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   void unlink(LocalStats *S) {
690b57cec5SDimitry Andric     ScopedLock L(Mutex);
70480093f4SDimitry Andric     StatsList.remove(S);
710b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
720b57cec5SDimitry Andric       add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   void get(uptr *S) const {
760b57cec5SDimitry Andric     ScopedLock L(Mutex);
770b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
78480093f4SDimitry Andric       S[I] = LocalStats::get(static_cast<StatType>(I));
79480093f4SDimitry Andric     for (const auto &Stats : StatsList) {
80480093f4SDimitry Andric       for (uptr I = 0; I < StatCount; I++)
81480093f4SDimitry Andric         S[I] += Stats.get(static_cast<StatType>(I));
820b57cec5SDimitry Andric     }
830b57cec5SDimitry Andric     // All stats must be non-negative.
840b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
850b57cec5SDimitry Andric       S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
860b57cec5SDimitry Andric   }
870b57cec5SDimitry Andric 
88*fe6060f1SDimitry Andric   void lock() { Mutex.lock(); }
89*fe6060f1SDimitry Andric   void unlock() { Mutex.unlock(); }
90*fe6060f1SDimitry Andric 
91*fe6060f1SDimitry Andric   void disable() { lock(); }
92*fe6060f1SDimitry Andric   void enable() { unlock(); }
93480093f4SDimitry Andric 
940b57cec5SDimitry Andric private:
950b57cec5SDimitry Andric   mutable HybridMutex Mutex;
96480093f4SDimitry Andric   DoublyLinkedList<LocalStats> StatsList;
970b57cec5SDimitry Andric };
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric } // namespace scudo
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric #endif // SCUDO_STATS_H_
102