6 #ifndef XENIUM_DETAIL_ALLOCATION_TRACKER_HPP
7 #define XENIUM_DETAIL_ALLOCATION_TRACKER_HPP
9 #ifndef TRACK_ALLOCATIONS
10 namespace xenium::reclamation::detail {
12 struct tracked_object {};
15 #define ALLOCATION_COUNTER(tracker)
16 #define ALLOCATION_TRACKER
17 #define ALLOCATION_TRACKING_FUNCTIONS
26 namespace xenium::reclamation::detail {
27 struct allocation_tracker;
29 template <
typename Tracker>
30 struct tracked_object {
31 tracked_object() noexcept { Tracker::count_allocation(); }
32 tracked_object(
const tracked_object&) noexcept { Tracker::count_allocation(); }
33 tracked_object(tracked_object&&) noexcept { Tracker::count_allocation(); }
34 virtual ~tracked_object() noexcept { Tracker::count_reclamation(); }
37 struct allocation_counter {
38 ~allocation_counter() { vals->dead =
true; }
41 values() : allocated_instances(), reclaimed_instances(), dead(false), next() {}
42 std::atomic<std::size_t> allocated_instances;
43 std::atomic<std::size_t> reclaimed_instances;
44 std::atomic<bool> dead;
47 void count_allocation() {
48 assert(vals->dead ==
false);
49 auto v = vals->allocated_instances.load(std::memory_order_relaxed);
50 vals->allocated_instances.store(v + 1, std::memory_order_relaxed);
52 void count_reclamation() {
53 assert(vals->dead ==
false);
54 auto v = vals->reclaimed_instances.load(std::memory_order_relaxed);
55 vals->reclaimed_instances.store(v + 1, std::memory_order_relaxed);
59 values* vals =
new values();
63 template <
typename Tracker>
64 struct registered_allocation_counter : allocation_counter {
65 registered_allocation_counter() {
66 auto h = Tracker::allocation_tracker.head.load(std::memory_order_relaxed);
69 }
while (!Tracker::allocation_tracker.head.compare_exchange_weak(h, vals, std::memory_order_release));
72 struct allocation_tracker {
73 std::pair<std::size_t, std::size_t> get_counters()
const {
74 std::size_t allocated_instances = collapsed_allocated_instances;
75 std::size_t reclaimed_instances = collapsed_reclaimed_instances;
76 auto p = head.load(std::memory_order_acquire);
78 allocated_instances += p->allocated_instances.load(std::memory_order_relaxed);
79 reclaimed_instances += p->reclaimed_instances.load(std::memory_order_relaxed);
82 return std::make_pair(allocated_instances, reclaimed_instances);
85 void collapse_counters() {
86 auto p = head.load(std::memory_order_acquire);
87 allocation_counter::values* remaining =
nullptr;
90 if (p->dead.load(std::memory_order_relaxed)) {
91 collapsed_allocated_instances += p->allocated_instances.load(std::memory_order_relaxed);
92 collapsed_reclaimed_instances += p->reclaimed_instances.load(std::memory_order_relaxed);
100 head.store(remaining, std::memory_order_relaxed);
105 friend struct registered_allocation_counter;
106 std::atomic<allocation_counter::values*> head;
107 std::size_t collapsed_allocated_instances = 0;
108 std::size_t collapsed_reclaimed_instances = 0;
112 #define ALLOCATION_COUNTER(tracker) detail::registered_allocation_counter<tracker> allocation_counter;
114 #define ALLOCATION_TRACKER inline static detail::allocation_tracker allocation_tracker;
116 #define ALLOCATION_TRACKING_FUNCTIONS \
117 template <typename> \
118 friend struct detail::tracked_object; \
119 static void count_allocation(); \
120 static void count_reclamation();