stats.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //===-- stats.h -------------------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef SCUDO_STATS_H_
  9. #define SCUDO_STATS_H_
  10. #include "atomic_helpers.h"
  11. #include "list.h"
  12. #include "mutex.h"
  13. #include <string.h>
  14. namespace scudo {
  15. // Memory allocator statistics
  16. enum StatType { StatAllocated, StatFree, StatMapped, StatCount };
  17. typedef uptr StatCounters[StatCount];
  18. // Per-thread stats, live in per-thread cache. We use atomics so that the
  19. // numbers themselves are consistent. But we don't use atomic_{add|sub} or a
  20. // lock, because those are expensive operations , and we only care for the stats
  21. // to be "somewhat" correct: eg. if we call GlobalStats::get while a thread is
  22. // LocalStats::add'ing, this is OK, we will still get a meaningful number.
  23. class LocalStats {
  24. public:
  25. void init() {
  26. for (uptr I = 0; I < StatCount; I++)
  27. DCHECK_EQ(get(static_cast<StatType>(I)), 0U);
  28. }
  29. void add(StatType I, uptr V) {
  30. V += atomic_load_relaxed(&StatsArray[I]);
  31. atomic_store_relaxed(&StatsArray[I], V);
  32. }
  33. void sub(StatType I, uptr V) {
  34. V = atomic_load_relaxed(&StatsArray[I]) - V;
  35. atomic_store_relaxed(&StatsArray[I], V);
  36. }
  37. void set(StatType I, uptr V) { atomic_store_relaxed(&StatsArray[I], V); }
  38. uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
  39. LocalStats *Next = nullptr;
  40. LocalStats *Prev = nullptr;
  41. private:
  42. atomic_uptr StatsArray[StatCount] = {};
  43. };
  44. // Global stats, used for aggregation and querying.
  45. class GlobalStats : public LocalStats {
  46. public:
  47. void init() { LocalStats::init(); }
  48. void link(LocalStats *S) {
  49. ScopedLock L(Mutex);
  50. StatsList.push_back(S);
  51. }
  52. void unlink(LocalStats *S) {
  53. ScopedLock L(Mutex);
  54. StatsList.remove(S);
  55. for (uptr I = 0; I < StatCount; I++)
  56. add(static_cast<StatType>(I), S->get(static_cast<StatType>(I)));
  57. }
  58. void get(uptr *S) const {
  59. ScopedLock L(Mutex);
  60. for (uptr I = 0; I < StatCount; I++)
  61. S[I] = LocalStats::get(static_cast<StatType>(I));
  62. for (const auto &Stats : StatsList) {
  63. for (uptr I = 0; I < StatCount; I++)
  64. S[I] += Stats.get(static_cast<StatType>(I));
  65. }
  66. // All stats must be non-negative.
  67. for (uptr I = 0; I < StatCount; I++)
  68. S[I] = static_cast<sptr>(S[I]) >= 0 ? S[I] : 0;
  69. }
  70. void lock() { Mutex.lock(); }
  71. void unlock() { Mutex.unlock(); }
  72. void disable() { lock(); }
  73. void enable() { unlock(); }
  74. private:
  75. mutable HybridMutex Mutex;
  76. DoublyLinkedList<LocalStats> StatsList;
  77. };
  78. } // namespace scudo
  79. #endif // SCUDO_STATS_H_