|
5 | 5 | * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | 6 | */ |
7 | 7 |
|
| 8 | +/* A MT-safe base allocator */ |
| 9 | + |
8 | 10 | #include <assert.h> |
| 11 | +#include <stdio.h> |
9 | 12 | #include <stdlib.h> |
10 | 13 |
|
11 | 14 | #include "base_alloc.h" |
12 | 15 | #include "base_alloc_global.h" |
| 16 | +#include "base_alloc_internal.h" |
13 | 17 | #include "utils_concurrency.h" |
14 | | - |
15 | | -#define SIZE_BA_POOL_CHUNK 128 |
| 18 | +#include "utils_math.h" |
16 | 19 |
|
17 | 20 | // global base allocator used by all providers and pools |
18 | | -static umf_ba_pool_t *BA_pool = NULL; |
19 | 21 | static UTIL_ONCE_FLAG ba_is_initialized = UTIL_ONCE_FLAG_INIT; |
20 | 22 |
|
| 23 | +// allocation classes need to be powers of 2 |
| 24 | +#define ALLOCATION_CLASSES \ |
| 25 | + { 16, 32, 64, 128 } |
| 26 | +#define NUM_ALLOCATION_CLASSES 4 |
| 27 | + |
| 28 | +struct base_alloc_t { |
| 29 | + size_t ac_sizes[NUM_ALLOCATION_CLASSES]; |
| 30 | + umf_ba_pool_t *ac[NUM_ALLOCATION_CLASSES]; |
| 31 | + size_t smallest_ac_size_log2; |
| 32 | +}; |
| 33 | + |
| 34 | +static struct base_alloc_t BASE_ALLOC = {.ac_sizes = ALLOCATION_CLASSES}; |
| 35 | + |
| 36 | +void umf_ba_destroy_global(void) { |
| 37 | + for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) { |
| 38 | + if (BASE_ALLOC.ac[i]) { |
| 39 | + umf_ba_destroy(BASE_ALLOC.ac[i]); |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
21 | 44 | static void umf_ba_create_global(void) { |
22 | | - assert(BA_pool == NULL); |
23 | | - BA_pool = umf_ba_create(SIZE_BA_POOL_CHUNK); |
24 | | - assert(BA_pool); |
| 45 | + for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) { |
| 46 | + // allocation classes need to be powers of 2 |
| 47 | + assert(0 == (BASE_ALLOC.ac_sizes[i] & (BASE_ALLOC.ac_sizes[i] - 1))); |
| 48 | + BASE_ALLOC.ac[i] = umf_ba_create(BASE_ALLOC.ac_sizes[i]); |
| 49 | + if (!BASE_ALLOC.ac[i]) { |
| 50 | + fprintf(stderr, |
| 51 | + "base_alloc: Error. Cannot create base alloc allocation " |
| 52 | + "class for size: %zu\n. Each allocation will fallback to " |
| 53 | + "allocating memory from the OS.", |
| 54 | + BASE_ALLOC.ac_sizes[i]); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + size_t smallestSize = BASE_ALLOC.ac_sizes[0]; |
| 59 | + BASE_ALLOC.smallest_ac_size_log2 = log2Utils(smallestSize); |
| 60 | + |
25 | 61 | #if defined(_WIN32) && !defined(UMF_SHARED_LIBRARY) |
26 | 62 | atexit(umf_ba_destroy_global); |
27 | 63 | #endif |
28 | 64 | } |
29 | 65 |
|
30 | | -void umf_ba_destroy_global(void) { |
31 | | - if (BA_pool) { |
32 | | - umf_ba_pool_t *pool = BA_pool; |
33 | | - BA_pool = NULL; |
34 | | - umf_ba_destroy(pool); |
| 66 | +// returns index of the allocation class for a given size |
| 67 | +static int size_to_idx(size_t size) { |
| 68 | + assert(size <= BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]); |
| 69 | + |
| 70 | + if (size <= BASE_ALLOC.ac_sizes[0]) { |
| 71 | + return 0; |
35 | 72 | } |
| 73 | + |
| 74 | + int isPowerOf2 = (0 == (size & (size - 1))); |
| 75 | + int index = |
| 76 | + (int)(log2Utils(size) + !isPowerOf2 - BASE_ALLOC.smallest_ac_size_log2); |
| 77 | + |
| 78 | + assert(index >= 0); |
| 79 | + assert(index < NUM_ALLOCATION_CLASSES); |
| 80 | + |
| 81 | + return index; |
36 | 82 | } |
37 | 83 |
|
38 | | -umf_ba_pool_t *umf_ba_get_pool(size_t size) { |
| 84 | +void *umf_ba_global_alloc(size_t size) { |
39 | 85 | util_init_once(&ba_is_initialized, umf_ba_create_global); |
40 | 86 |
|
41 | | - if (!BA_pool) { |
42 | | - return NULL; |
| 87 | + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
| 88 | + fprintf(stderr, |
| 89 | + "base_alloc: allocation size larger than the biggest " |
| 90 | + "allocation class. Falling back to OS memory allocation.\n"); |
| 91 | + return ba_os_alloc(size); |
43 | 92 | } |
44 | 93 |
|
45 | | - // TODO: a specific class-size base allocator can be returned here |
46 | | - assert(size <= SIZE_BA_POOL_CHUNK); |
| 94 | + int ac_index = size_to_idx(size); |
| 95 | + if (!BASE_ALLOC.ac[ac_index]) { |
| 96 | + // if creating ac failed, fall back to os allocation |
| 97 | + fprintf(stderr, "base_alloc: allocation class not created. Falling " |
| 98 | + "back to OS memory allocation.\n"); |
| 99 | + return ba_os_alloc(size); |
| 100 | + } |
| 101 | + |
| 102 | + return umf_ba_alloc(BASE_ALLOC.ac[ac_index]); |
| 103 | +} |
| 104 | + |
| 105 | +void umf_ba_global_free(void *ptr, size_t size) { |
| 106 | + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
| 107 | + ba_os_free(ptr, size); |
| 108 | + return; |
| 109 | + } |
47 | 110 |
|
48 | | - if (size > SIZE_BA_POOL_CHUNK) { |
49 | | - return NULL; |
| 111 | + int ac_index = size_to_idx(size); |
| 112 | + if (!BASE_ALLOC.ac[ac_index]) { |
| 113 | + // if creating ac failed, memory must have been allocated by os |
| 114 | + ba_os_free(ptr, size); |
| 115 | + return; |
50 | 116 | } |
51 | 117 |
|
52 | | - return BA_pool; |
| 118 | + umf_ba_free(BASE_ALLOC.ac[ac_index], ptr); |
53 | 119 | } |
0 commit comments