xref: /freebsd/contrib/llvm-project/compiler-rt/lib/scudo/standalone/stats.h (revision 68d75eff68281c1b445e3010bb975eae07aac225)
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"
130b57cec5SDimitry Andric #include "mutex.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include <string.h>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric namespace scudo {
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric // Memory allocator statistics
20*68d75effSDimitry Andric enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric typedef uptr StatCounters[StatCount];
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric // Per-thread stats, live in per-thread cache. We use atomics so that the
250b57cec5SDimitry Andric // numbers themselves are consistent. But we don't use atomic_{add|sub} or a
260b57cec5SDimitry Andric // lock, because those are expensive operations , and we only care for the stats
270b57cec5SDimitry Andric // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
280b57cec5SDimitry Andric // LocalStats::add'ing, this is OK, we will still get a meaningful number.
290b57cec5SDimitry Andric class LocalStats {
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric   void initLinkerInitialized() {}
320b57cec5SDimitry Andric   void init() { memset(this, 0, sizeof(*this)); }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric   void add(StatType I, uptr V) {
350b57cec5SDimitry Andric     V += atomic_load_relaxed(&StatsArray[I]);
360b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
370b57cec5SDimitry Andric   }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   void sub(StatType I, uptr V) {
400b57cec5SDimitry Andric     V = atomic_load_relaxed(&StatsArray[I]) - V;
410b57cec5SDimitry Andric     atomic_store_relaxed(&StatsArray[I], V);
420b57cec5SDimitry Andric   }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric private:
490b57cec5SDimitry Andric   friend class GlobalStats;
500b57cec5SDimitry Andric   atomic_uptr StatsArray[StatCount];
510b57cec5SDimitry Andric   LocalStats *Next;
520b57cec5SDimitry Andric   LocalStats *Prev;
530b57cec5SDimitry Andric };
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
560b57cec5SDimitry Andric class GlobalStats : public LocalStats {
570b57cec5SDimitry Andric public:
580b57cec5SDimitry Andric   void initLinkerInitialized() {
590b57cec5SDimitry Andric     Next = this;
600b57cec5SDimitry Andric     Prev = this;
610b57cec5SDimitry Andric   }
620b57cec5SDimitry Andric   void init() {
630b57cec5SDimitry Andric     memset(this, 0, sizeof(*this));
640b57cec5SDimitry Andric     initLinkerInitialized();
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   void link(LocalStats *S) {
680b57cec5SDimitry Andric     ScopedLock L(Mutex);
690b57cec5SDimitry Andric     S->Next = Next;
700b57cec5SDimitry Andric     S->Prev = this;
710b57cec5SDimitry Andric     Next->Prev = S;
720b57cec5SDimitry Andric     Next = S;
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   void unlink(LocalStats *S) {
760b57cec5SDimitry Andric     ScopedLock L(Mutex);
770b57cec5SDimitry Andric     S->Prev->Next = S->Next;
780b57cec5SDimitry Andric     S->Next->Prev = S->Prev;
790b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
800b57cec5SDimitry Andric       add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   void get(uptr *S) const {
840b57cec5SDimitry Andric     memset(S, 0, StatCount * sizeof(uptr));
850b57cec5SDimitry Andric     ScopedLock L(Mutex);
860b57cec5SDimitry Andric     const LocalStats *Stats = this;
870b57cec5SDimitry Andric     for (;;) {
880b57cec5SDimitry Andric       for (uptr I = 0; I < StatCount; I++)
890b57cec5SDimitry Andric         S[I] += Stats->get(static_cast<StatType>(I));
900b57cec5SDimitry Andric       Stats = Stats->Next;
910b57cec5SDimitry Andric       if (Stats == this)
920b57cec5SDimitry Andric         break;
930b57cec5SDimitry Andric     }
940b57cec5SDimitry Andric     // All stats must be non-negative.
950b57cec5SDimitry Andric     for (uptr I = 0; I < StatCount; I++)
960b57cec5SDimitry Andric       S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric private:
1000b57cec5SDimitry Andric   mutable HybridMutex Mutex;
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric } // namespace scudo
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric #endif // SCUDO_STATS_H_
106