10b57cec5SDimitry Andric //===-- sanitizer_allocator_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 // Part of the Sanitizer Allocator.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric #ifndef SANITIZER_ALLOCATOR_H
130b57cec5SDimitry Andric #error This file must be included inside sanitizer_allocator.h
140b57cec5SDimitry Andric #endif
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric // Memory allocator statistics
170b57cec5SDimitry Andric enum AllocatorStat {
180b57cec5SDimitry Andric   AllocatorStatAllocated,
190b57cec5SDimitry Andric   AllocatorStatMapped,
200b57cec5SDimitry Andric   AllocatorStatCount
210b57cec5SDimitry Andric };
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric typedef uptr AllocatorStatCounters[AllocatorStatCount];
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric // Per-thread stats, live in per-thread cache.
260b57cec5SDimitry Andric class AllocatorStats {
270b57cec5SDimitry Andric  public:
Init()28*06c3fb27SDimitry Andric   void Init() { internal_memset(this, 0, sizeof(*this)); }
Add(AllocatorStat i,uptr v)290b57cec5SDimitry Andric   void Add(AllocatorStat i, uptr v) {
30*06c3fb27SDimitry Andric     atomic_fetch_add(&stats_[i], v, memory_order_relaxed);
310b57cec5SDimitry Andric   }
320b57cec5SDimitry Andric 
Sub(AllocatorStat i,uptr v)330b57cec5SDimitry Andric   void Sub(AllocatorStat i, uptr v) {
34*06c3fb27SDimitry Andric     atomic_fetch_sub(&stats_[i], v, memory_order_relaxed);
350b57cec5SDimitry Andric   }
360b57cec5SDimitry Andric 
Set(AllocatorStat i,uptr v)370b57cec5SDimitry Andric   void Set(AllocatorStat i, uptr v) {
380b57cec5SDimitry Andric     atomic_store(&stats_[i], v, memory_order_relaxed);
390b57cec5SDimitry Andric   }
400b57cec5SDimitry Andric 
Get(AllocatorStat i)410b57cec5SDimitry Andric   uptr Get(AllocatorStat i) const {
420b57cec5SDimitry Andric     return atomic_load(&stats_[i], memory_order_relaxed);
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric  private:
460b57cec5SDimitry Andric   friend class AllocatorGlobalStats;
470b57cec5SDimitry Andric   AllocatorStats *next_;
480b57cec5SDimitry Andric   AllocatorStats *prev_;
490b57cec5SDimitry Andric   atomic_uintptr_t stats_[AllocatorStatCount];
500b57cec5SDimitry Andric };
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric // Global stats, used for aggregation and querying.
530b57cec5SDimitry Andric class AllocatorGlobalStats : public AllocatorStats {
540b57cec5SDimitry Andric  public:
Init()550b57cec5SDimitry Andric   void Init() {
560b57cec5SDimitry Andric     internal_memset(this, 0, sizeof(*this));
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric 
Register(AllocatorStats * s)590b57cec5SDimitry Andric   void Register(AllocatorStats *s) {
600b57cec5SDimitry Andric     SpinMutexLock l(&mu_);
61*06c3fb27SDimitry Andric     LazyInit();
620b57cec5SDimitry Andric     s->next_ = next_;
630b57cec5SDimitry Andric     s->prev_ = this;
640b57cec5SDimitry Andric     next_->prev_ = s;
650b57cec5SDimitry Andric     next_ = s;
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
Unregister(AllocatorStats * s)680b57cec5SDimitry Andric   void Unregister(AllocatorStats *s) {
690b57cec5SDimitry Andric     SpinMutexLock l(&mu_);
700b57cec5SDimitry Andric     s->prev_->next_ = s->next_;
710b57cec5SDimitry Andric     s->next_->prev_ = s->prev_;
720b57cec5SDimitry Andric     for (int i = 0; i < AllocatorStatCount; i++)
730b57cec5SDimitry Andric       Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
740b57cec5SDimitry Andric   }
750b57cec5SDimitry Andric 
Get(AllocatorStatCounters s)760b57cec5SDimitry Andric   void Get(AllocatorStatCounters s) const {
770b57cec5SDimitry Andric     internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
780b57cec5SDimitry Andric     SpinMutexLock l(&mu_);
790b57cec5SDimitry Andric     const AllocatorStats *stats = this;
80*06c3fb27SDimitry Andric     for (; stats;) {
810b57cec5SDimitry Andric       for (int i = 0; i < AllocatorStatCount; i++)
820b57cec5SDimitry Andric         s[i] += stats->Get(AllocatorStat(i));
830b57cec5SDimitry Andric       stats = stats->next_;
840b57cec5SDimitry Andric       if (stats == this)
850b57cec5SDimitry Andric         break;
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric     // All stats must be non-negative.
880b57cec5SDimitry Andric     for (int i = 0; i < AllocatorStatCount; i++)
890b57cec5SDimitry Andric       s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric  private:
LazyInit()93*06c3fb27SDimitry Andric   void LazyInit() {
94*06c3fb27SDimitry Andric     if (!next_) {
95*06c3fb27SDimitry Andric       next_ = this;
96*06c3fb27SDimitry Andric       prev_ = this;
97*06c3fb27SDimitry Andric     }
98*06c3fb27SDimitry Andric   }
99*06c3fb27SDimitry Andric 
1000b57cec5SDimitry Andric   mutable StaticSpinMutex mu_;
1010b57cec5SDimitry Andric };
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric 
104