xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/stats.h (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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"
13*480093f4SDimitry 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:
320b57cec5SDimitry Andric   void initLinkerInitialized() {}
330b57cec5SDimitry Andric   void init() { memset(this, 0, sizeof(*this)); }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   void add(StatType I, uptr V) {
360b57cec5SDimitry Andric     V += atomic_load_relaxed(&StatsArray[I]);
370b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   void sub(StatType I, uptr V) {
410b57cec5SDimitry Andric     V = atomic_load_relaxed(&StatsArray[I]) - V;
420b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   LocalStats *Next;
500b57cec5SDimitry Andric   LocalStats *Prev;
51*480093f4SDimitry Andric 
52*480093f4SDimitry Andric private:
53*480093f4SDimitry Andric   atomic_uptr StatsArray[StatCount];
540b57cec5SDimitry Andric };
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
570b57cec5SDimitry Andric class GlobalStats : public LocalStats {
580b57cec5SDimitry Andric public:
59*480093f4SDimitry Andric   void initLinkerInitialized() {}
600b57cec5SDimitry Andric   void init() {
610b57cec5SDimitry Andric     memset(this, 0, sizeof(*this));
620b57cec5SDimitry Andric     initLinkerInitialized();
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   void link(LocalStats *S) {
660b57cec5SDimitry Andric     ScopedLock L(Mutex);
67*480093f4SDimitry Andric     StatsList.push_back(S);
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   void unlink(LocalStats *S) {
710b57cec5SDimitry Andric     ScopedLock L(Mutex);
72*480093f4SDimitry Andric     StatsList.remove(S);
730b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
740b57cec5SDimitry Andric       add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   void get(uptr *S) const {
780b57cec5SDimitry Andric     ScopedLock L(Mutex);
790b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
80*480093f4SDimitry Andric       S[I] = LocalStats::get(static_cast<StatType>(I));
81*480093f4SDimitry Andric     for (const auto &Stats : StatsList) {
82*480093f4SDimitry Andric       for (uptr I = 0; I < StatCount; I++)
83*480093f4SDimitry Andric         S[I] += Stats.get(static_cast<StatType>(I));
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric     // All stats must be non-negative.
860b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
870b57cec5SDimitry Andric       S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric 
90*480093f4SDimitry Andric   void disable() { Mutex.lock(); }
91*480093f4SDimitry Andric   void enable() { Mutex.unlock(); }
92*480093f4SDimitry Andric 
930b57cec5SDimitry Andric private:
940b57cec5SDimitry Andric   mutable HybridMutex Mutex;
95*480093f4SDimitry Andric   DoublyLinkedList<LocalStats> StatsList;
960b57cec5SDimitry Andric };
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric } // namespace scudo
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric #endif // SCUDO_STATS_H_
101