6 #ifndef XENIUM_DETAIL_ALLOCATION_TRACKER_HPP
7 #define XENIUM_DETAIL_ALLOCATION_TRACKER_HPP
9 #ifndef TRACK_ALLOCATIONS
10 namespace xenium {
namespace reclamation {
namespace detail {
12 struct tracked_object {};
15 #define ALLOCATION_COUNTER(tracker)
16 #define ALLOCATION_TRACKER
17 #define ALLOCATION_TRACKING_FUNCTIONS
26 namespace xenium {
namespace reclamation {
namespace 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
39 ~allocation_counter() { vals->dead =
true; }
44 allocated_instances(),
45 reclaimed_instances(),
49 std::atomic<std::size_t> allocated_instances;
50 std::atomic<std::size_t> reclaimed_instances;
51 std::atomic<bool> dead;
54 void count_allocation()
56 assert(vals->dead ==
false);
57 auto v = vals->allocated_instances.load(std::memory_order_relaxed);
58 vals->allocated_instances.store(v + 1, std::memory_order_relaxed);
60 void count_reclamation()
62 assert(vals->dead ==
false);
63 auto v = vals->reclaimed_instances.load(std::memory_order_relaxed);
64 vals->reclaimed_instances.store(v + 1, std::memory_order_relaxed);
67 values* vals =
new values();;
70 template <
typename Tracker>
71 struct registered_allocation_counter : allocation_counter
73 registered_allocation_counter()
75 auto h = Tracker::allocation_tracker.head.load(std::memory_order_relaxed);
79 }
while (!Tracker::allocation_tracker.head.compare_exchange_weak(h, vals, std::memory_order_release));
82 struct allocation_tracker
84 std::pair<std::size_t, std::size_t> get_counters()
const
86 std::size_t allocated_instances = collapsed_allocated_instances;
87 std::size_t reclaimed_instances = collapsed_reclaimed_instances;
88 auto p = head.load(std::memory_order_acquire);
91 allocated_instances += p->allocated_instances.load(std::memory_order_relaxed);
92 reclaimed_instances += p->reclaimed_instances.load(std::memory_order_relaxed);
95 return std::make_pair(allocated_instances, reclaimed_instances);
98 void collapse_counters()
100 auto p = head.load(std::memory_order_acquire);
101 allocation_counter::values* remaining =
nullptr;
105 if (p->dead.load(std::memory_order_relaxed))
107 collapsed_allocated_instances += p->allocated_instances.load(std::memory_order_relaxed);
108 collapsed_reclaimed_instances += p->reclaimed_instances.load(std::memory_order_relaxed);
118 head.store(remaining, std::memory_order_relaxed);
122 friend struct registered_allocation_counter;
123 std::atomic<allocation_counter::values*> head;
124 std::size_t collapsed_allocated_instances = 0;
125 std::size_t collapsed_reclaimed_instances = 0;
129 #define ALLOCATION_COUNTER(tracker) \
130 detail::registered_allocation_counter<tracker> allocation_counter;
132 #define ALLOCATION_TRACKER \
133 inline static detail::allocation_tracker allocation_tracker;
135 #define ALLOCATION_TRACKING_FUNCTIONS \
136 template <typename> friend struct detail::tracked_object; \
137 static void count_allocation(); \
138 static void count_reclamation();