Skip to content

Commit 729dbe0

Browse files
committed
Add linear base allocator
Add a MT-safe linear base allocator. It is useful for a few, small and different size allocations for a most/whole life-time of an application (free() is not available). Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 7c52a0d commit 729dbe0

File tree

5 files changed

+200
-0
lines changed

5 files changed

+200
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(UMF_LIBS umf_utils)
1010

1111
set(UMF_SOURCES
1212
base_alloc/base_alloc.c
13+
base_alloc/base_alloc_linear.c
1314
memory_pool.c
1415
memory_provider.c
1516
memory_provider_get_last_failed.c

src/base_alloc/base_alloc_linear.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#include <assert.h>
9+
#include <stdint.h>
10+
11+
#include "base_alloc_internal.h"
12+
#include "base_alloc_linear.h"
13+
#include "utils_common.h"
14+
#include "utils_concurrency.h"
15+
16+
// minimum size of a single pool of the linear base allocator
17+
#define MINIMUM_LINEAR_POOL_SIZE (ba_os_get_page_size())
18+
19+
// alignment of the linear base allocator
20+
#define MEMORY_ALIGNMENT (8)
21+
22+
// metadata of the linear base allocator
23+
typedef struct {
24+
size_t pool_size;
25+
os_mutex_t *lock;
26+
char *data_ptr;
27+
size_t size_left;
28+
} umf_ba_main_linear_pool_meta_t;
29+
30+
// pool of the linear base allocator
31+
struct umf_ba_linear_pool {
32+
umf_ba_main_linear_pool_meta_t metadata;
33+
char data[]; // data area starts here
34+
};
35+
36+
umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) {
37+
size_t mutex_size = align_size(util_mutex_get_size(), MEMORY_ALIGNMENT);
38+
size_t metadata_size = sizeof(umf_ba_main_linear_pool_meta_t);
39+
pool_size = pool_size + metadata_size + mutex_size;
40+
if (pool_size < MINIMUM_LINEAR_POOL_SIZE) {
41+
pool_size = MINIMUM_LINEAR_POOL_SIZE;
42+
}
43+
44+
pool_size = align_size(pool_size, ba_os_get_page_size());
45+
46+
umf_ba_linear_pool_t *pool = (umf_ba_linear_pool_t *)ba_os_alloc(pool_size);
47+
if (!pool) {
48+
return NULL;
49+
}
50+
51+
void *data_ptr = &pool->data;
52+
size_t size_left = pool_size - offsetof(umf_ba_linear_pool_t, data);
53+
54+
align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT);
55+
56+
pool->metadata.pool_size = pool_size;
57+
pool->metadata.data_ptr = data_ptr;
58+
pool->metadata.size_left = size_left;
59+
60+
// allocate and init lock
61+
pool->metadata.lock = util_mutex_init(pool->metadata.data_ptr);
62+
if (!pool->metadata.lock) {
63+
ba_os_free(pool, pool_size);
64+
return NULL;
65+
}
66+
67+
pool->metadata.data_ptr += mutex_size; // lock is here
68+
pool->metadata.size_left -= mutex_size; // for lock
69+
70+
return pool;
71+
}
72+
73+
void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
74+
size_t aligned_size = align_size(size, MEMORY_ALIGNMENT);
75+
76+
util_mutex_lock(pool->metadata.lock);
77+
if (pool->metadata.size_left < aligned_size) {
78+
util_mutex_unlock(pool->metadata.lock);
79+
return NULL; // out of memory
80+
}
81+
82+
void *ptr = pool->metadata.data_ptr;
83+
pool->metadata.data_ptr += aligned_size;
84+
pool->metadata.size_left -= aligned_size;
85+
util_mutex_unlock(pool->metadata.lock);
86+
87+
return ptr;
88+
}
89+
90+
void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) {
91+
util_mutex_destroy_not_free(pool->metadata.lock);
92+
ba_os_free(pool, pool->metadata.pool_size);
93+
}

src/base_alloc/base_alloc_linear.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
/*
9+
* A MT-safe linear base allocator.
10+
* Useful for a few, small and different size allocations
11+
* for a most/whole life-time of an application
12+
* (since free() is not available).
13+
*/
14+
15+
#ifndef UMF_BASE_ALLOC_LINEAR_H
16+
#define UMF_BASE_ALLOC_LINEAR_H 1
17+
18+
#include <stddef.h>
19+
20+
typedef struct umf_ba_linear_pool umf_ba_linear_pool_t;
21+
22+
umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size);
23+
void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size);
24+
void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool);
25+
26+
#endif /* UMF_BASE_ALLOC_LINEAR_H */

test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,7 @@ if(LINUX)
117117
add_umf_test(NAME base_alloc
118118
SRCS test_base_alloc.c
119119
LIBS umf_utils)
120+
add_umf_test(NAME base_alloc_linear
121+
SRCS test_base_alloc_linear.c
122+
LIBS umf_utils)
120123
endif()

test/test_base_alloc_linear.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#include <assert.h>
9+
#include <pthread.h>
10+
#include <stdio.h>
11+
#include <string.h>
12+
#include <sys/syscall.h>
13+
#include <unistd.h>
14+
15+
#include "base_alloc_linear.h"
16+
#include "test_helpers.h"
17+
18+
#define NTHREADS 10
19+
#define ITERATIONS 1000
20+
#define MAX_ALLOCATION_SIZE 1024
21+
22+
static void *start_routine(void *arg) {
23+
struct buffer_t {
24+
unsigned char *ptr;
25+
size_t size;
26+
} buffer[ITERATIONS];
27+
umf_ba_linear_pool_t *pool = (umf_ba_linear_pool_t *)arg;
28+
29+
long TID = syscall(SYS_gettid);
30+
31+
for (int i = 0; i < ITERATIONS; i++) {
32+
buffer[i].size = (rand() * MAX_ALLOCATION_SIZE) / RAND_MAX;
33+
buffer[i].ptr = umf_ba_linear_alloc(pool, buffer[i].size);
34+
memset(buffer[i].ptr, (i + TID) & 0xFF, buffer[i].size);
35+
}
36+
37+
for (int i = 0; i < ITERATIONS; i++) {
38+
for (int k = 0; k < buffer[i].size; k++) {
39+
if (*(buffer[i].ptr + k) != ((i + TID) & 0xFF)) {
40+
fprintf(
41+
stderr,
42+
"i = %i k = %i, *(buffer[i].ptr + k) = %i != ((i + TID) & "
43+
"0xFF) = %li\n",
44+
i, k, *(buffer[i].ptr + k), ((i + TID) & 0xFF));
45+
}
46+
UT_ASSERTeq(*(buffer[i].ptr + k), ((i + TID) & 0xFF));
47+
}
48+
}
49+
50+
return NULL;
51+
}
52+
53+
int main() {
54+
pthread_t thread[NTHREADS];
55+
umf_ba_linear_pool_t *pool = umf_ba_linear_create(MAX_ALLOCATION_SIZE);
56+
57+
for (int i = 0; i < NTHREADS; i++) {
58+
int ret = pthread_create(&thread[i], NULL, start_routine, pool);
59+
if (ret) {
60+
fprintf(stderr, "pthread_create() failed!\n");
61+
UT_ASSERTeq(ret, 0);
62+
}
63+
}
64+
65+
for (int i = 0; i < NTHREADS; i++) {
66+
void *retval;
67+
int ret = pthread_join(thread[i], &retval);
68+
if (ret) {
69+
fprintf(stderr, "pthread_join() failed!\n");
70+
UT_ASSERTeq(ret, 0);
71+
}
72+
}
73+
74+
umf_ba_linear_destroy(pool);
75+
76+
return 0;
77+
}

0 commit comments

Comments
 (0)