Skip to content

Commit 6b910ad

Browse files
authored
Merge pull request #177 from ldorau/Add_linear_base_allocator
Add linear base allocator
2 parents 3e8fc35 + bcbe798 commit 6b910ad

File tree

9 files changed

+237
-14
lines changed

9 files changed

+237
-14
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.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ umf_ba_pool_t *umf_ba_create(size_t size) {
144144
char *data_ptr = (char *)&pool->data;
145145
size_t size_left = pool_size - offsetof(umf_ba_pool_t, data);
146146

147+
align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT);
148+
147149
// allocate and init free_lock
148150
pool->metadata.free_lock = util_mutex_init(data_ptr);
149151
if (!pool->metadata.free_lock) {
@@ -178,9 +180,12 @@ void *umf_ba_alloc(umf_ba_pool_t *pool) {
178180
pool->metadata.n_pools++;
179181
#endif /* NDEBUG */
180182

181-
size_t size =
183+
char *data_ptr = (char *)&new_pool->data;
184+
size_t size_left =
182185
pool->metadata.pool_size - offsetof(umf_ba_next_pool_t, data);
183-
ba_divide_memory_into_chunks(pool, &new_pool->data, size);
186+
187+
align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT);
188+
ba_divide_memory_into_chunks(pool, data_ptr, size_left);
184189
}
185190

186191
umf_ba_chunk_t *chunk = pool->metadata.free_list;

src/base_alloc/base_alloc_linear.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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 (sizeof(uintptr_t))
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+
// init lock
61+
os_mutex_t *lock = util_mutex_init(&pool->metadata.lock);
62+
if (!lock) {
63+
ba_os_free(pool, pool_size);
64+
return NULL;
65+
}
66+
67+
return pool;
68+
}
69+
70+
void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) {
71+
size_t aligned_size = align_size(size, MEMORY_ALIGNMENT);
72+
73+
util_mutex_lock(&pool->metadata.lock);
74+
if (pool->metadata.size_left < aligned_size) {
75+
util_mutex_unlock(&pool->metadata.lock);
76+
return NULL; // out of memory
77+
}
78+
79+
void *ptr = pool->metadata.data_ptr;
80+
pool->metadata.data_ptr += aligned_size;
81+
pool->metadata.size_left -= aligned_size;
82+
util_mutex_unlock(&pool->metadata.lock);
83+
84+
return ptr;
85+
}
86+
87+
void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) {
88+
util_mutex_destroy_not_free(&pool->metadata.lock);
89+
ba_os_free(pool, pool->metadata.pool_size);
90+
}

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 */

src/utils/utils_common.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#ifndef UMF_COMMON_H
1111
#define UMF_COMMON_H 1
1212

13+
#include <stdint.h>
1314
#include <stdio.h>
1415
#include <stdlib.h>
1516
#include <string.h>
@@ -77,6 +78,25 @@ static inline void *Zalloc(size_t s) {
7778
} \
7879
} while (0)
7980

81+
// align a pointer and a size
82+
static inline void align_ptr_size(void **ptr, size_t *size, size_t alignment) {
83+
uintptr_t p = (uintptr_t)*ptr;
84+
size_t s = *size;
85+
86+
// align pointer to 'alignment' bytes and adjust the size
87+
size_t rest = p & (alignment - 1);
88+
if (rest) {
89+
p += alignment - rest;
90+
s -= alignment - rest;
91+
}
92+
93+
ASSERT((p & (alignment - 1)) == 0);
94+
ASSERT((s & (alignment - 1)) == 0);
95+
96+
*ptr = (void *)p;
97+
*size = s;
98+
}
99+
80100
static inline size_t align_size(size_t size, size_t alignment) {
81101
// align size to 'alignment' bytes
82102
size_t rest = size & (alignment - 1);

src/utils/utils_concurrency.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@
1414
#if defined(_WIN32)
1515
#include <windows.h>
1616
#else
17+
#include <pthread.h>
1718
#include <stdatomic.h>
1819
#endif
1920

2021
#ifdef __cplusplus
2122
extern "C" {
2223
#endif
2324

24-
struct os_mutex_t;
25-
26-
typedef struct os_mutex_t os_mutex_t;
25+
typedef struct os_mutex_t {
26+
#ifdef _WIN32
27+
CRITICAL_SECTION lock;
28+
#else
29+
pthread_mutex_t lock;
30+
#endif
31+
} os_mutex_t;
2732

2833
size_t util_mutex_get_size(void);
2934
os_mutex_t *util_mutex_init(void *ptr);

src/utils/utils_windows_concurrency.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,10 @@
99

1010
#include "utils_concurrency.h"
1111

12-
typedef struct {
13-
CRITICAL_SECTION lock;
14-
} internal_os_mutex_t;
15-
16-
size_t util_mutex_get_size(void) { return sizeof(internal_os_mutex_t); }
12+
size_t util_mutex_get_size(void) { return sizeof(os_mutex_t); }
1713

1814
os_mutex_t *util_mutex_init(void *ptr) {
19-
internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)ptr;
15+
os_mutex_t *mutex_internal = (os_mutex_t *)ptr;
2016
InitializeCriticalSection(&mutex_internal->lock);
2117
return (os_mutex_t *)mutex_internal;
2218
}
@@ -26,7 +22,7 @@ os_mutex_t *util_mutex_create(void) {
2622
}
2723

2824
void util_mutex_destroy_not_free(os_mutex_t *mutex) {
29-
internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex;
25+
os_mutex_t *mutex_internal = (os_mutex_t *)mutex;
3026
DeleteCriticalSection(&mutex_internal->lock);
3127
}
3228

@@ -35,7 +31,7 @@ void util_mutex_destroy(os_mutex_t *mutex) {
3531
}
3632

3733
int util_mutex_lock(os_mutex_t *mutex) {
38-
internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex;
34+
os_mutex_t *mutex_internal = (os_mutex_t *)mutex;
3935
EnterCriticalSection(&mutex_internal->lock);
4036

4137
if (mutex_internal->lock.RecursionCount > 1) {
@@ -47,7 +43,7 @@ int util_mutex_lock(os_mutex_t *mutex) {
4743
}
4844

4945
int util_mutex_unlock(os_mutex_t *mutex) {
50-
internal_os_mutex_t *mutex_internal = (internal_os_mutex_t *)mutex;
46+
os_mutex_t *mutex_internal = (os_mutex_t *)mutex;
5147
LeaveCriticalSection(&mutex_internal->lock);
5248
return 0;
5349
}

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)