GCC Code Coverage Report


Directory: ./
File: src/utilities/allocator.h
Date: 2023-04-27 00:55:30
Exec Total Coverage
Lines: 41 42 97.6%
Functions: 1089 1185 91.9%
Branches: 32 54 59.3%

Line Branch Exec Source
1 #ifndef LYTHON_UTILITIES_ALLOCATOR_HEADER
2 #define LYTHON_UTILITIES_ALLOCATOR_HEADER
3
4 #include <functional>
5 #include <memory>
6 #include <unordered_map>
7 #include <vector>
8
9 #include "logging/logging.h"
10
11 namespace lython {
12
13 void show_alloc_stats();
14
15 namespace meta {
16
17 // NOTE: All those should not depend on each other during deinit time
18 // https://isocpp.org/wiki/faq/ctors#construct-on-first-use-v2
19 struct Stat {
20 int allocated = 0;
21 int deallocated = 0;
22 int bytes = 0;
23 int size_alloc = 0;
24 int size_free = 0;
25 int startup_count = 0;
26 };
27
28 bool& is_type_registry_available();
29
30 struct TypeRegistry {
31 std::vector<Stat> stat;
32 bool print_stats = false;
33 std::unordered_map<int, std::string> id_to_name;
34 int type_counter = 0;
35
36 static TypeRegistry& instance() {
37
4/8
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6662 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
6670 static TypeRegistry obj;
38 6670 return obj;
39 }
40
41 TypeRegistry() { is_type_registry_available() = true; }
42
43 ~TypeRegistry() {
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (print_stats) {
45 show_alloc_stats();
46 }
47
48 8 is_type_registry_available() = false;
49 8 }
50 };
51
52 inline std::vector<Stat>& stats() { return TypeRegistry::instance().stat; }
53
54 inline int& _get_id() { return TypeRegistry::instance().type_counter; }
55
56 inline int _new_id() {
57 631 auto r = _get_id();
58 631 _get_id() += 1;
59
1/2
✓ Branch 3 taken 631 times.
✗ Branch 4 not taken.
631 stats().push_back(Stat());
60 631 return r;
61 }
62
63 inline std::unordered_map<int, std::string>& typenames() {
64 903 return TypeRegistry::instance().id_to_name;
65 }
66
67 // Generate a unique ID for a given type
68 template <typename T>
69 int type_id() {
70
4/8
✓ Branch 0 taken 2392 times.
✓ Branch 1 taken 133217 times.
✓ Branch 3 taken 2392 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2392 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
268072 static int _id = _new_id();
71 268072 return _id;
72 }
73
74 template <typename T>
75 int _register_type_once(const char* str) {
76
4/4
✓ Branch 1 taken 672 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 664 times.
1343 if (!is_type_registry_available())
77 16 return 0;
78
79
1/2
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
1327 auto tid = type_id<T>();
80
2/4
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 666 times.
✗ Branch 5 not taken.
1327 auto result = typenames().find(tid);
81
82
3/4
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 131 times.
✓ Branch 6 taken 535 times.
1327 if (result == typenames().end()) {
83
4/8
✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 131 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 131 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 131 times.
✗ Branch 11 not taken.
259 typenames().insert({type_id<T>(), str});
84 }
85 1327 return tid;
86 }
87
88 // Insert a type name override
89 template <typename T>
90 void override_typename(const char* str) {
91
1/1
✓ Branch 1 taken 2340 times.
4680 auto tid = type_id<T>();
92
3/3
✓ Branch 1 taken 2340 times.
✓ Branch 4 taken 2340 times.
✓ Branch 7 taken 2340 times.
4680 typenames()[tid] = str;
93 4680 }
94
95 // Insert a type name override
96 template <typename T>
97 108 const char* register_type(const char* str) {
98
4/8
✓ Branch 0 taken 566 times.
✓ Branch 1 taken 53216 times.
✓ Branch 3 taken 566 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 566 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
106886 static int _ = _register_type_once<T>(str);
99 106886 return str;
100 }
101
102 // Return the type name of a function
103 // You can specialize it to override
104 template <typename T>
105 const char* type_name() {
106 auto result = typenames().find(type_id<T>());
107
108 if (result == typenames().end()) {
109 const char* name = typeid(T).name();
110 register_type<T>(name);
111 return "<none>";
112 }
113
114 return (result->second).c_str();
115 };
116
117 inline const char* type_name(int class_id) {
118 568 std::string const& name = typenames()[class_id];
119 568 return name.c_str();
120 };
121
122 template <typename T>
123 Stat& get_stat() {
124 320220 return stats()[type_id<T>()];
125 }
126
127 // When type info is not available at compile time
128 // often when deleting a derived class
129 inline Stat& get_stat(int class_id) { return stats()[class_id]; }
130
131 } // namespace meta
132
133 inline void show_alloc_stats_on_destroy(bool enabled) {
134 1 meta::TypeRegistry::instance().print_stats = enabled;
135 1 }
136
137 namespace device {
138
139 template <typename Device>
140 class DeviceAllocatorTrait {
141 static void* malloc(std::size_t n) { return Device::malloc(n); }
142
143 static bool free(void* ptr, std::size_t n) { return Device::free(ptr, n); }
144 };
145
146 #ifdef __CUDACC__
147 struct CUDA: public DeviceAllocatorTrait<CUDA> {
148 void* malloc(std::size_t n);
149 bool free(void* ptr, std::size_t n);
150 };
151 #endif
152
153 struct CPU: public DeviceAllocatorTrait<CPU> {
154 static void* malloc(std::size_t n);
155
156 static bool free(void* ptr, std::size_t n);
157 };
158
159 } // namespace device
160
161 inline void manual_free(int class_id, std::size_t n) {
162 2439 meta::get_stat(class_id).deallocated += 1;
163 2439 meta::get_stat(class_id).size_free += int(n);
164 2439 }
165
166 template <typename T, typename Device>
167 class Allocator {
168 public:
169 using size_type = std::size_t;
170 using difference_type = std::ptrdiff_t;
171 using pointer = T*;
172 using const_pointer = const T*;
173 using reference = T&;
174 using const_reference = const T&;
175 using value_type = T;
176
177 template <typename _Tp1>
178 struct rebind {
179 using other = Allocator<_Tp1, Device>;
180 };
181
182 bool operator==(Allocator const&) const { return true; }
183
184 bool operator!=(Allocator const& alloc) const { return !(*this == alloc); }
185
186 // template <typename... Args>
187 // static void construct(T *value, Args &&...args) {
188 // new ((void *)value) T(std::forward<Args>(args)...);
189 // }
190
191 static void deallocate(pointer p, std::size_t n) {
192 47766 manual_free(meta::type_id<T>(), n);
193 47766 Device::free(static_cast<void*>(p), n * sizeof(T));
194 47766 return;
195 }
196
197 static T* allocate(std::size_t n, const void* = nullptr) {
198 106740 meta::register_type<T>(typeid(T).name());
199 106740 meta::get_stat<T>().allocated += 1;
200 106740 meta::get_stat<T>().size_alloc += int(n);
201 106740 meta::get_stat<T>().bytes = int(sizeof(T));
202 106740 return static_cast<T*>(Device::malloc(n * sizeof(T)));
203 }
204
205 Allocator() noexcept {}
206
207 Allocator(const Allocator& a) noexcept {}
208
209 template <class U>
210 Allocator(const Allocator<U, Device>& a) noexcept {}
211
212 ~Allocator() noexcept = default;
213 };
214
215 template <typename V>
216 using SharedPtr = std::shared_ptr<V>;
217
218 template <typename _Tp, typename... _Args>
219 inline SharedPtr<_Tp> make_shared(_Args&&... __args) {
220 typedef typename std::remove_cv<_Tp>::type _Tp_nc;
221 return std::allocate_shared<_Tp>(Allocator<_Tp_nc, device::CPU>(),
222 std::forward<_Args>(__args)...);
223 }
224
225 template <typename V>
226 using UniquePtr = std::unique_ptr<V>;
227
228 template <typename _Tp, typename... _Args>
229 inline UniquePtr<_Tp> make_unique(_Args&&... __args) {
230 auto ptr = Allocator<_Tp, device::CPU>().allocate(1);
231 return UniquePtr<_Tp>(new (ptr) _Tp(std::forward<_Args>(__args)...));
232 }
233
234 } // namespace lython
235
236 #endif
237