Skip to content

Commit ba67586

Browse files
committed
Add abstraction on top of ba_alloc
which supports arbitrary size allocations and routes the alloc requests to specific allocation classes or to ba_alloc_os. Use this abstraction instead of a single global pool of fixed size.
1 parent 5876bdc commit ba67586

20 files changed

+207
-135
lines changed

src/base_alloc/base_alloc_global.c

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,96 @@
55
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
*/
77

8-
#include <assert.h>
8+
/* A MT-safe base allocator */
99

10+
#include "base_alloc_global.h"
1011
#include "base_alloc.h"
12+
#include "base_alloc_internal.h"
13+
#include "utils_math.h"
1114

12-
#define SIZE_BA_POOL_CHUNK 128
15+
#include <stdio.h>
1316

14-
// global base allocator used by all providers and pools
15-
static umf_ba_pool_t *BA_pool = NULL;
17+
// allocation classes need to be powers of 2
18+
#define ALLOCATION_CLASSES \
19+
{ 16, 32, 64, 128 }
20+
#define NUM_ALLOCATION_CLASSES 4
1621

17-
int umf_ba_create_global(void) {
18-
assert(BA_pool == NULL);
22+
struct base_alloc_t {
23+
size_t ac_sizes[NUM_ALLOCATION_CLASSES];
24+
umf_ba_pool_t *ac[NUM_ALLOCATION_CLASSES];
25+
size_t smallest_ac_size_log2;
26+
};
1927

20-
BA_pool = umf_ba_create(SIZE_BA_POOL_CHUNK);
21-
if (!BA_pool) {
22-
return -1;
28+
static struct base_alloc_t BASE_ALLOC = {.ac_sizes = ALLOCATION_CLASSES};
29+
30+
void umf_ba_create_global(void) {
31+
for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) {
32+
// allocation classes need to be powers of 2
33+
assert(0 == (BASE_ALLOC.ac_sizes[i] & (BASE_ALLOC.ac_sizes[i] - 1)));
34+
BASE_ALLOC.ac[i] = umf_ba_create(BASE_ALLOC.ac_sizes[i]);
35+
if (!BASE_ALLOC.ac[i]) {
36+
fprintf(stderr,
37+
"Cannot create base alloc allocation class for size: %zu\n",
38+
BASE_ALLOC.ac_sizes[i]);
39+
}
2340
}
2441

25-
return 0;
42+
size_t smallestSize = BASE_ALLOC.ac_sizes[0];
43+
BASE_ALLOC.smallest_ac_size_log2 = log2Utils(smallestSize);
2644
}
2745

2846
void umf_ba_destroy_global(void) {
29-
assert(BA_pool);
30-
umf_ba_destroy(BA_pool);
31-
BA_pool = NULL;
47+
for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) {
48+
if (BASE_ALLOC.ac[i]) {
49+
umf_ba_destroy(BASE_ALLOC.ac[i]);
50+
}
51+
}
52+
}
53+
54+
// returns index of the allocation class for a give size
55+
static int size_to_idx(size_t size) {
56+
assert(size <= BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]);
57+
58+
if (size <= BASE_ALLOC.ac_sizes[0]) {
59+
return 0;
60+
}
61+
62+
int isPowerOf2 = (0 == (size & (size - 1)));
63+
int index =
64+
(int)(log2Utils(size) + !isPowerOf2 - BASE_ALLOC.smallest_ac_size_log2);
65+
66+
assert(index >= 0);
67+
assert(index < NUM_ALLOCATION_CLASSES);
68+
69+
return index;
70+
}
71+
72+
void *umf_ba_global_alloc(size_t size) {
73+
if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) {
74+
return ba_os_alloc(size);
75+
}
76+
77+
int ac_index = size_to_idx(size);
78+
if (!BASE_ALLOC.ac[ac_index]) {
79+
// if creating ac failed, fall back to os allocation
80+
return ba_os_alloc(size);
81+
}
82+
83+
return umf_ba_alloc(BASE_ALLOC.ac[ac_index]);
3284
}
3385

34-
umf_ba_pool_t *umf_ba_get_pool(size_t size) {
35-
// TODO: a specific class-size base allocator can be returned here
36-
assert(BA_pool);
37-
assert(size <= SIZE_BA_POOL_CHUNK);
86+
void umf_ba_global_free(void *ptr, size_t size) {
87+
if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) {
88+
ba_os_free(ptr, size);
89+
return;
90+
}
3891

39-
if (size > SIZE_BA_POOL_CHUNK) {
40-
return NULL;
92+
int ac_index = size_to_idx(size);
93+
if (!BASE_ALLOC.ac[ac_index]) {
94+
// if creating ac failed, memory must have been allocated by os
95+
ba_os_free(ptr, size);
96+
return;
4197
}
4298

43-
return BA_pool;
99+
umf_ba_free(BASE_ALLOC.ac[ac_index], ptr);
44100
}

src/base_alloc/base_alloc_global.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
extern "C" {
1515
#endif
1616

17-
int umf_ba_create_global(void);
17+
void umf_ba_create_global(void);
1818
void umf_ba_destroy_global(void);
19-
umf_ba_pool_t *umf_ba_get_pool(size_t size);
19+
20+
void *umf_ba_global_alloc(size_t size);
21+
void umf_ba_global_free(void *ptr, size_t size);
2022

2123
#ifdef __cplusplus
2224
}

src/memory_pool_default.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,21 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
2525
}
2626

2727
umf_result_t ret = UMF_RESULT_SUCCESS;
28-
umf_ba_pool_t *base_allocator = umf_ba_get_pool(sizeof(umf_memory_pool_t));
29-
if (!base_allocator) {
30-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
31-
}
32-
33-
umf_memory_pool_handle_t pool = umf_ba_alloc(base_allocator);
28+
umf_memory_pool_handle_t pool =
29+
umf_ba_global_alloc(sizeof(umf_memory_pool_t));
3430
if (!pool) {
3531
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
3632
}
3733

3834
assert(ops->version == UMF_VERSION_CURRENT);
3935

40-
pool->base_allocator = base_allocator;
4136
pool->provider = provider;
4237
pool->own_provider = false;
4338

4439
pool->ops = *ops;
4540
ret = ops->initialize(pool->provider, params, &pool->pool_priv);
4641
if (ret != UMF_RESULT_SUCCESS) {
47-
umf_ba_free(base_allocator, pool);
42+
umf_ba_global_free(pool, sizeof(umf_memory_pool_t));
4843
return ret;
4944
}
5045

@@ -61,7 +56,7 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) {
6156
umfMemoryProviderDestroy(hProvider);
6257
}
6358
// TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized)
64-
umf_ba_free(hPool->base_allocator, hPool);
59+
umf_ba_global_free(hPool, sizeof(umf_memory_pool_t));
6560
}
6661

6762
umf_result_t umfFree(void *ptr) {

src/memory_pool_internal.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ typedef struct umf_memory_pool_t {
3131
umf_memory_provider_handle_t provider;
3232
// Tells whether memory provider is owned by the pool.
3333
bool own_provider;
34-
35-
// saved pointer to the global base allocator
36-
umf_ba_pool_t *base_allocator;
3734
} umf_memory_pool_t;
3835

3936
umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,

src/memory_pool_tracking.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,8 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
2626
}
2727

2828
umf_result_t ret = UMF_RESULT_SUCCESS;
29-
umf_ba_pool_t *base_allocator = umf_ba_get_pool(sizeof(umf_memory_pool_t));
30-
if (!base_allocator) {
31-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
32-
}
33-
34-
umf_memory_pool_handle_t pool = umf_ba_alloc(base_allocator);
29+
umf_memory_pool_handle_t pool =
30+
umf_ba_global_alloc(sizeof(umf_memory_pool_t));
3531
if (!pool) {
3632
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
3733
}
@@ -44,7 +40,6 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
4440
goto err_provider_create;
4541
}
4642

47-
pool->base_allocator = base_allocator;
4843
pool->own_provider = false;
4944

5045
pool->ops = *ops;
@@ -59,7 +54,7 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
5954
err_pool_init:
6055
umfMemoryProviderDestroy(pool->provider);
6156
err_provider_create:
62-
umf_ba_free(base_allocator, pool);
57+
umf_ba_global_free(pool, sizeof(umf_memory_pool_t));
6358
return ret;
6459
}
6560

@@ -74,7 +69,7 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) {
7469
// Destroy tracking provider.
7570
umfMemoryProviderDestroy(hPool->provider);
7671
// TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized)
77-
umf_ba_free(hPool->base_allocator, hPool);
72+
umf_ba_global_free(hPool, sizeof(umf_memory_pool_t));
7873
}
7974

8075
umf_result_t umfFree(void *ptr) {

src/memory_provider.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222
typedef struct umf_memory_provider_t {
2323
umf_memory_provider_ops_t ops;
2424
void *provider_priv;
25-
26-
// saved pointer to the global base allocator
27-
umf_ba_pool_t *base_allocator;
2825
} umf_memory_provider_t;
2926

3027
umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops,
@@ -35,26 +32,20 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops,
3532
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
3633
}
3734

38-
umf_ba_pool_t *base_allocator =
39-
umf_ba_get_pool(sizeof(umf_memory_provider_t));
40-
if (!base_allocator) {
41-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
42-
}
43-
44-
umf_memory_provider_handle_t provider = umf_ba_alloc(base_allocator);
35+
umf_memory_provider_handle_t provider =
36+
umf_ba_global_alloc(sizeof(umf_memory_provider_t));
4537
if (!provider) {
4638
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
4739
}
4840

4941
assert(ops->version == UMF_VERSION_CURRENT);
5042

5143
provider->ops = *ops;
52-
provider->base_allocator = base_allocator;
5344

5445
void *provider_priv;
5546
umf_result_t ret = ops->initialize(params, &provider_priv);
5647
if (ret != UMF_RESULT_SUCCESS) {
57-
umf_ba_free(base_allocator, provider);
48+
umf_ba_global_free(provider, sizeof(umf_memory_provider_t));
5849
return ret;
5950
}
6051

@@ -67,7 +58,7 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops,
6758

6859
void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider) {
6960
hProvider->ops.finalize(hProvider->provider_priv);
70-
umf_ba_free(hProvider->base_allocator, hProvider);
61+
umf_ba_global_free(hProvider, sizeof(umf_memory_provider_t));
7162
}
7263

7364
static void

src/memory_target.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,20 @@ umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops,
2424
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
2525
}
2626

27-
umf_ba_pool_t *base_allocator =
28-
umf_ba_get_pool(sizeof(umf_memory_target_t));
29-
if (!base_allocator) {
30-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
31-
}
32-
3327
umf_memory_target_handle_t target =
34-
(umf_memory_target_t *)umf_ba_alloc(base_allocator);
28+
(umf_memory_target_t *)umf_ba_global_alloc(sizeof(umf_memory_target_t));
3529
if (!target) {
3630
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
3731
}
3832

3933
assert(ops->version == UMF_VERSION_CURRENT);
4034

41-
target->base_allocator = base_allocator;
4235
target->ops = ops;
4336

4437
void *target_priv;
4538
umf_result_t ret = ops->initialize(params, &target_priv);
4639
if (ret != UMF_RESULT_SUCCESS) {
47-
umf_ba_free(base_allocator, target);
40+
umf_ba_global_free(target, sizeof(umf_memory_target_t));
4841
return ret;
4942
}
5043

@@ -58,5 +51,5 @@ umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops,
5851
void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget) {
5952
assert(memoryTarget);
6053
memoryTarget->ops->finalize(memoryTarget->priv);
61-
umf_ba_free(memoryTarget->base_allocator, memoryTarget);
54+
umf_ba_global_free(memoryTarget, sizeof(umf_memory_target_t));
6255
}

src/memory_target.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ typedef struct umf_memory_target_ops_t umf_memory_target_ops_t;
2424
typedef struct umf_memory_target_t {
2525
const umf_memory_target_ops_t *ops;
2626
void *priv;
27-
28-
// saved pointer to the global base allocator
29-
umf_ba_pool_t *base_allocator;
3027
} umf_memory_target_t;
3128

3229
typedef umf_memory_target_t *umf_memory_target_handle_t;

src/memory_targets/memory_target_numa.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222

2323
struct numa_memory_target_t {
2424
size_t id;
25-
26-
// saved pointer to the global base allocator
27-
umf_ba_pool_t *base_allocator;
2825
};
2926

3027
static umf_result_t numa_initialize(void *params, void **memTarget) {
@@ -35,27 +32,19 @@ static umf_result_t numa_initialize(void *params, void **memTarget) {
3532
struct umf_numa_memory_target_config_t *config =
3633
(struct umf_numa_memory_target_config_t *)params;
3734

38-
umf_ba_pool_t *base_allocator =
39-
umf_ba_get_pool(sizeof(struct numa_memory_target_t));
40-
if (!base_allocator) {
41-
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
42-
}
43-
44-
struct numa_memory_target_t *numaTarget = umf_ba_alloc(base_allocator);
35+
struct numa_memory_target_t *numaTarget =
36+
umf_ba_global_alloc(sizeof(struct numa_memory_target_t));
4537
if (!numaTarget) {
4638
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
4739
}
4840

49-
numaTarget->base_allocator = base_allocator;
5041
numaTarget->id = config->id;
5142
*memTarget = numaTarget;
5243
return UMF_RESULT_SUCCESS;
5344
}
5445

5546
static void numa_finalize(void *memTarget) {
56-
struct numa_memory_target_t *numaTarget =
57-
(struct numa_memory_target_t *)memTarget;
58-
umf_ba_free(numaTarget->base_allocator, memTarget);
47+
umf_ba_global_free(memTarget, sizeof(struct numa_memory_target_t));
5948
}
6049

6150
// sets maxnode and allocates and initializes mask based on provided memory targets

src/memspace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <umf/memspace.h>
1414

15+
#include "base_alloc_global.h"
1516
#include "memory_target.h"
1617
#include "memory_target_ops.h"
1718
#include "memspace_internal.h"
@@ -105,5 +106,5 @@ void umfMemspaceDestroy(umf_memspace_handle_t memspace) {
105106
}
106107

107108
umf_ba_linear_destroy(memspace->linear_allocator);
108-
umf_ba_free(memspace->base_allocator, memspace);
109+
umf_ba_global_free(memspace, sizeof(struct umf_memspace_t));
109110
}

src/memspace_internal.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ struct umf_memspace_t {
2424
size_t size;
2525
umf_memory_target_handle_t *nodes;
2626

27-
// saved pointer to the global base allocator
28-
umf_ba_pool_t *base_allocator;
29-
3027
// own local linear base allocator
3128
umf_ba_linear_pool_t *linear_allocator;
3229
};

0 commit comments

Comments
 (0)