|
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 | + BASE_ALLOC.ac[i] = NULL; |
| 41 | + } |
| 42 | + } |
| 43 | +} |
| 44 | + |
21 | 45 | 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); |
| 46 | + for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) { |
| 47 | + // allocation classes need to be powers of 2 |
| 48 | + assert(0 == (BASE_ALLOC.ac_sizes[i] & (BASE_ALLOC.ac_sizes[i] - 1))); |
| 49 | + BASE_ALLOC.ac[i] = umf_ba_create(BASE_ALLOC.ac_sizes[i]); |
| 50 | + if (!BASE_ALLOC.ac[i]) { |
| 51 | + fprintf(stderr, |
| 52 | + "base_alloc: Error. Cannot create base alloc allocation " |
| 53 | + "class for size: %zu\n. Each allocation will fallback to " |
| 54 | + "allocating memory from the OS.", |
| 55 | + BASE_ALLOC.ac_sizes[i]); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + size_t smallestSize = BASE_ALLOC.ac_sizes[0]; |
| 60 | + BASE_ALLOC.smallest_ac_size_log2 = log2Utils(smallestSize); |
| 61 | + |
25 | 62 | #if defined(_WIN32) && !defined(UMF_SHARED_LIBRARY)
|
26 | 63 | atexit(umf_ba_destroy_global);
|
27 | 64 | #endif
|
28 | 65 | }
|
29 | 66 |
|
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); |
| 67 | +// returns index of the allocation class for a given size |
| 68 | +static int size_to_idx(size_t size) { |
| 69 | + assert(size <= BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]); |
| 70 | + |
| 71 | + if (size <= BASE_ALLOC.ac_sizes[0]) { |
| 72 | + return 0; |
35 | 73 | }
|
| 74 | + |
| 75 | + int isPowerOf2 = (0 == (size & (size - 1))); |
| 76 | + int index = |
| 77 | + (int)(log2Utils(size) + !isPowerOf2 - BASE_ALLOC.smallest_ac_size_log2); |
| 78 | + |
| 79 | + assert(index >= 0); |
| 80 | + assert(index < NUM_ALLOCATION_CLASSES); |
| 81 | + |
| 82 | + return index; |
36 | 83 | }
|
37 | 84 |
|
38 |
| -umf_ba_pool_t *umf_ba_get_pool(size_t size) { |
| 85 | +void *umf_ba_global_alloc(size_t size) { |
39 | 86 | util_init_once(&ba_is_initialized, umf_ba_create_global);
|
40 | 87 |
|
41 |
| - if (!BA_pool) { |
42 |
| - return NULL; |
| 88 | + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
| 89 | + fprintf(stderr, |
| 90 | + "base_alloc: allocation size larger than the biggest " |
| 91 | + "allocation class. Falling back to OS memory allocation.\n"); |
| 92 | + return ba_os_alloc(size); |
43 | 93 | }
|
44 | 94 |
|
45 |
| - // TODO: a specific class-size base allocator can be returned here |
46 |
| - assert(size <= SIZE_BA_POOL_CHUNK); |
| 95 | + int ac_index = size_to_idx(size); |
| 96 | + if (!BASE_ALLOC.ac[ac_index]) { |
| 97 | + // if creating ac failed, fall back to os allocation |
| 98 | + fprintf(stderr, "base_alloc: allocation class not created. Falling " |
| 99 | + "back to OS memory allocation.\n"); |
| 100 | + return ba_os_alloc(size); |
| 101 | + } |
| 102 | + |
| 103 | + return umf_ba_alloc(BASE_ALLOC.ac[ac_index]); |
| 104 | +} |
| 105 | + |
| 106 | +void umf_ba_global_free(void *ptr, size_t size) { |
| 107 | + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { |
| 108 | + ba_os_free(ptr, size); |
| 109 | + return; |
| 110 | + } |
47 | 111 |
|
48 |
| - if (size > SIZE_BA_POOL_CHUNK) { |
49 |
| - return NULL; |
| 112 | + int ac_index = size_to_idx(size); |
| 113 | + if (!BASE_ALLOC.ac[ac_index]) { |
| 114 | + // if creating ac failed, memory must have been allocated by os |
| 115 | + ba_os_free(ptr, size); |
| 116 | + return; |
50 | 117 | }
|
51 | 118 |
|
52 |
| - return BA_pool; |
| 119 | + umf_ba_free(BASE_ALLOC.ac[ac_index], ptr); |
53 | 120 | }
|
0 commit comments