|
14 | 14 | #include "base_alloc.h"
|
15 | 15 | #include "base_alloc_global.h"
|
16 | 16 | #include "base_alloc_internal.h"
|
| 17 | +#include "utils_common.h" |
17 | 18 | #include "utils_concurrency.h"
|
18 | 19 | #include "utils_math.h"
|
19 | 20 |
|
20 | 21 | // global base allocator used by all providers and pools
|
21 | 22 | static UTIL_ONCE_FLAG ba_is_initialized = UTIL_ONCE_FLAG_INIT;
|
22 | 23 |
|
23 |
| -// allocation classes need to be powers of 2 |
| 24 | +// allocation classes need to be consecutive powers of 2 |
24 | 25 | #define ALLOCATION_CLASSES \
|
25 | 26 | { 16, 32, 64, 128 }
|
26 | 27 | #define NUM_ALLOCATION_CLASSES 4
|
@@ -82,41 +83,114 @@ static int size_to_idx(size_t size) {
|
82 | 83 | return index;
|
83 | 84 | }
|
84 | 85 |
|
85 |
| -void *umf_ba_global_alloc(size_t size) { |
| 86 | +static void *transform_ptr(void *ptr, size_t size, size_t alignment) { |
| 87 | + assert(ptr); |
| 88 | + |
| 89 | + void *user_ptr; |
| 90 | + if (alignment <= sizeof(size_t)) { |
| 91 | + user_ptr = (void *)((uintptr_t)ptr + sizeof(size_t)); |
| 92 | + } else { |
| 93 | + user_ptr = (void *)ALIGN_UP((uintptr_t)ptr + sizeof(size_t), alignment); |
| 94 | + } |
| 95 | + |
| 96 | + size_t ptr_offset_from_original = (uintptr_t)user_ptr - (uintptr_t)ptr; |
| 97 | + |
| 98 | + size_t *metadata_loc = (size_t *)((char *)user_ptr - sizeof(size_t)); |
| 99 | + *metadata_loc = size | (ptr_offset_from_original << 32); |
| 100 | + |
| 101 | + return user_ptr; |
| 102 | +} |
| 103 | + |
| 104 | +static void *get_original_alloc(void *user_ptr, size_t *total_size, |
| 105 | + size_t *usable_size) { |
| 106 | + assert(user_ptr); |
| 107 | + |
| 108 | + size_t *metadata_loc = (size_t *)((char *)user_ptr - sizeof(size_t)); |
| 109 | + |
| 110 | + size_t stored_size = *metadata_loc & ((1ULL << 32) - 1); |
| 111 | + size_t ptr_offset_from_original = *metadata_loc >> 32; |
| 112 | + |
| 113 | + void *original_ptr = |
| 114 | + (void *)((uintptr_t)user_ptr - ptr_offset_from_original); |
| 115 | + |
| 116 | + if (total_size) { |
| 117 | + *total_size = stored_size; |
| 118 | + } |
| 119 | + |
| 120 | + if (usable_size) { |
| 121 | + *usable_size = stored_size - ptr_offset_from_original; |
| 122 | + } |
| 123 | + |
| 124 | + return original_ptr; |
| 125 | +} |
| 126 | + |
| 127 | +void *umf_ba_global_aligned_alloc(size_t size, size_t alignment) { |
86 | 128 | util_init_once(&ba_is_initialized, umf_ba_create_global);
|
87 | 129 |
|
| 130 | + // for metadata |
| 131 | + size += sizeof(size_t); |
| 132 | + |
| 133 | + if (alignment > sizeof(size_t)) { |
| 134 | + size += alignment; |
| 135 | + } |
| 136 | + |
88 | 137 | if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) {
|
89 | 138 | #ifndef NDEBUG
|
90 | 139 | fprintf(stderr,
|
91 | 140 | "base_alloc: allocation size larger than the biggest "
|
92 | 141 | "allocation class. Falling back to OS memory allocation.\n");
|
93 | 142 | #endif
|
94 |
| - return ba_os_alloc(size); |
| 143 | + return transform_ptr(ba_os_alloc(size), size, alignment); |
95 | 144 | }
|
96 | 145 |
|
97 | 146 | int ac_index = size_to_idx(size);
|
98 | 147 | if (!BASE_ALLOC.ac[ac_index]) {
|
99 | 148 | // if creating ac failed, fall back to os allocation
|
100 | 149 | fprintf(stderr, "base_alloc: allocation class not created. Falling "
|
101 | 150 | "back to OS memory allocation.\n");
|
102 |
| - return ba_os_alloc(size); |
| 151 | + return transform_ptr(ba_os_alloc(size), size, alignment); |
103 | 152 | }
|
104 | 153 |
|
105 |
| - return umf_ba_alloc(BASE_ALLOC.ac[ac_index]); |
| 154 | + return transform_ptr(umf_ba_alloc(BASE_ALLOC.ac[ac_index]), size, |
| 155 | + alignment); |
106 | 156 | }
|
107 | 157 |
|
108 |
| -void umf_ba_global_free(void *ptr, size_t size) { |
109 |
| - if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
110 |
| - ba_os_free(ptr, size); |
| 158 | +void *umf_ba_global_alloc(size_t size) { |
| 159 | + return umf_ba_global_aligned_alloc(size, sizeof(size_t)); |
| 160 | +} |
| 161 | + |
| 162 | +void umf_ba_global_free(void *ptr) { |
| 163 | + if (!ptr) { |
111 | 164 | return;
|
112 | 165 | }
|
113 | 166 |
|
114 |
| - int ac_index = size_to_idx(size); |
| 167 | + size_t total_size; |
| 168 | + ptr = get_original_alloc(ptr, &total_size, NULL); |
| 169 | + |
| 170 | + if (total_size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
| 171 | + ba_os_free(ptr, total_size); |
| 172 | + return; |
| 173 | + } |
| 174 | + |
| 175 | + int ac_index = size_to_idx(total_size); |
115 | 176 | if (!BASE_ALLOC.ac[ac_index]) {
|
116 | 177 | // if creating ac failed, memory must have been allocated by os
|
117 |
| - ba_os_free(ptr, size); |
| 178 | + ba_os_free(ptr, total_size); |
118 | 179 | return;
|
119 | 180 | }
|
120 | 181 |
|
121 | 182 | umf_ba_free(BASE_ALLOC.ac[ac_index], ptr);
|
122 | 183 | }
|
| 184 | + |
| 185 | +size_t umf_ba_global_malloc_usable_size(void *ptr) { |
| 186 | + if (!ptr) { |
| 187 | + return 0; |
| 188 | + } |
| 189 | + |
| 190 | + size_t usable_size; |
| 191 | + get_original_alloc(ptr, NULL, &usable_size); |
| 192 | + |
| 193 | + assert(usable_size >= sizeof(size_t)); |
| 194 | + |
| 195 | + return usable_size; |
| 196 | +} |
0 commit comments