Skip to content

Commit 4be720b

Browse files
committed
Optimize arena allocator add helper functions
Refactor 'arena_alloc' to insert newly allocated blocks at the head of the block list, improving allocation efficiency. This reduces pointer chasing during allocation and enables recently freed memory to be reused more quickly. Introduce 'arena_calloc', 'arena_memdup', 'arena_strdup', and 'arena_realloc' to extend the arena allocator's API: - 'arena_calloc': Allocate zero-initialized memory blocks. - 'arena_memdup': Duplicate arbitrary data into arena-managed memory. - 'arena_strdup': Copy null-terminated strings into the arena. - 'arena_realloc': Resize existing arena-managed allocations. These improvements lay the foundation for replacing standard 'malloc', 'calloc', 'realloc', and 'free' with the arena allocator, providing better performance, consistent memory handling, and simpler batch deallocation throughout the project.
1 parent 7163605 commit 4be720b

File tree

1 file changed

+148
-36
lines changed

1 file changed

+148
-36
lines changed

src/globals.c

Lines changed: 148 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ int elf_data_start;
8989

9090
/**
9191
* arena_block_create() - Creates a new arena block with given capacity.
92-
* The created arena block is guaranteed to be zero-initialized.
9392
* @capacity: The capacity of the arena block. Must be positive.
9493
*
9594
* Return: The pointer of created arena block. NULL if failed to allocate.
@@ -99,16 +98,16 @@ arena_block_t *arena_block_create(int capacity)
9998
arena_block_t *block = malloc(sizeof(arena_block_t));
10099

101100
if (!block) {
102-
printf("Failed to allocate memory for arena block\n");
103-
exit(1);
101+
printf("Failed to allocate memory for arena block structure\n");
102+
abort();
104103
}
105104

106-
block->memory = calloc(capacity, sizeof(char));
105+
block->memory = malloc(capacity * sizeof(char));
107106

108107
if (!block->memory) {
109-
printf("Failed to allocate memory for arena block\n");
108+
printf("Failed to allocate memory for arena block buffer\n");
110109
free(block);
111-
exit(1);
110+
abort();
112111
}
113112

114113
block->capacity = capacity;
@@ -117,6 +116,16 @@ arena_block_t *arena_block_create(int capacity)
117116
return block;
118117
}
119118

119+
/**
120+
* arena_block_free() - Free a single arena block and its memory buffer.
121+
* @block: Pointer to the arena_block_t to free. Must not be NULL.
122+
*/
123+
void arena_block_free(arena_block_t *block)
124+
{
125+
free(block->memory);
126+
free(block);
127+
}
128+
120129
/**
121130
* arena_init() - Initializes the given arena with initial capacity.
122131
* @initial_capacity: The initial capacity of the arena. Must be positive.
@@ -126,6 +135,10 @@ arena_block_t *arena_block_create(int capacity)
126135
arena_t *arena_init(int initial_capacity)
127136
{
128137
arena_t *arena = malloc(sizeof(arena_t));
138+
if (!arena) {
139+
printf("Failed to allocate memory for arena structure\n");
140+
abort();
141+
}
129142
arena->head = arena_block_create(initial_capacity);
130143
return arena;
131144
}
@@ -141,47 +154,147 @@ arena_t *arena_init(int initial_capacity)
141154
*/
142155
void *arena_alloc(arena_t *arena, int size)
143156
{
144-
char *ptr;
145-
arena_block_t *block = arena->head;
157+
if (size <= 0) {
158+
printf("arena_alloc: size must be positive\n");
159+
abort();
160+
}
146161

147-
while (block) {
148-
if (block->offset + size <= block->capacity) {
149-
ptr = block->memory + block->offset;
150-
block->offset += size;
151-
return ptr;
152-
}
153-
if (!block->next)
154-
break;
155-
block = block->next;
162+
/* Align to PTR_SIZE bytes */
163+
size = (size + PTR_SIZE - 1) & ~(PTR_SIZE - 1);
164+
165+
if (!arena->head || arena->head->offset + size > arena->head->capacity) {
166+
/* Need a new block: choose capacity = max(DEFAULT_ARENA_SIZE, size) */
167+
int new_capacity =
168+
(size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE);
169+
arena_block_t *new_block = arena_block_create(new_capacity);
170+
new_block->next = arena->head;
171+
arena->head = new_block;
156172
}
157173

158-
/* If no space is available, create a new block
159-
* Allocate at least 256 KiB or the requested size
160-
*/
161-
int new_capacity = size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE;
162-
arena_block_t *new_block = arena_block_create(new_capacity);
174+
void *ptr = arena->head->memory + arena->head->offset;
175+
arena->head->offset += size;
176+
return ptr;
177+
}
163178

164-
if (!new_block)
165-
return NULL;
179+
/**
180+
* arena_calloc() - arena_alloc() plus explicit zero‑initialization.
181+
* @arena: The arena to allocate memory from. Must not be NULL.
182+
* @n: Number of elements.
183+
* @size: Size of each element in bytes.
184+
*
185+
* Internally calls arena_alloc(n * size) and then fills the entire region
186+
* with zero bytes.
187+
*
188+
* Return: Pointer to zero-initialized memory.
189+
*/
190+
void *arena_calloc(arena_t *arena, int n, int size)
191+
{
192+
if (n * size == 0) {
193+
printf("arena_calloc: cannot allocate 0 bytes\n");
194+
abort();
195+
}
196+
197+
int total = n * size;
198+
void *ptr = arena_alloc(arena, total);
199+
200+
int *w_ptr = ptr;
201+
int w_count = total >> 2;
202+
int b_index = w_count << 2;
203+
204+
for (int i = 0; i < w_count; ++i)
205+
w_ptr[i] = 0;
206+
207+
char *b_ptr = ptr;
208+
while (b_index < total)
209+
b_ptr[b_index++] = 0;
166210

167-
block->next = new_block;
168-
ptr = new_block->memory + new_block->offset;
169-
new_block->offset += size;
170211
return ptr;
171212
}
172213

173214
/**
174-
* arena_reset() - Resets the given arena by resetting all blocks' offset to 0.
175-
* @arena: The arena to reset. Must not be NULL.
215+
* arena_realloc() - Reallocate a previously allocated region within the arena
216+
* to a different size.
217+
*
218+
* Behaviors:
219+
* 1. If oldptr == NULL and oldsz == 0, act like malloc.
220+
* 2. If newsz <= oldsz, return oldptr immediately.
221+
* 3. Grow in place if oldptr is the last allocation in the current block.
222+
* 4. Otherwise, allocate a new region and copy old data.
223+
*
224+
* @arena: Pointer to the arena. Must not be NULL.
225+
* @oldptr: Pointer to the previously allocated memory in the arena.
226+
* @oldsz: Original size (in bytes) of that allocation.
227+
* @newsz: New desired size (in bytes).
228+
*
229+
* Return: Pointer to the reallocated (resized) memory region.
176230
*/
177-
void arena_reset(arena_t *arena)
231+
void *arena_realloc(arena_t *arena, char *oldptr, int oldsz, int newsz)
178232
{
179-
arena_block_t *block = arena->head;
233+
/* act like malloc */
234+
if (oldptr == NULL) {
235+
if (oldsz != 0) {
236+
printf("arena_realloc: oldptr == NULL requires oldsz == 0\n");
237+
abort();
238+
}
239+
return arena_alloc(arena, newsz);
240+
}
241+
if (oldsz == 0) {
242+
printf("arena_realloc: oldptr != NULL requires oldsz > 0\n");
243+
abort();
244+
}
180245

181-
while (block) {
182-
block->offset = 0;
183-
block = block->next;
246+
/* return oldptr immediately */
247+
if (newsz <= oldsz) {
248+
return oldptr;
184249
}
250+
251+
/* From here on, oldptr != NULL and newsz > oldsz and oldsz != 0 */
252+
int delta = newsz - oldsz;
253+
arena_block_t *blk = arena->head;
254+
char *block_end = blk->memory + blk->offset;
255+
256+
/* grow in place if oldptr is the last allocation in the current block */
257+
if (oldptr + oldsz == block_end && blk->offset + delta <= blk->capacity) {
258+
blk->offset += delta;
259+
return oldptr;
260+
}
261+
262+
/* allocate a new region and copy old data */
263+
void *newptr = arena_alloc(arena, newsz);
264+
memcpy(newptr, oldptr, oldsz);
265+
return newptr;
266+
}
267+
268+
/**
269+
* arena_strdup() - Duplicate a NULL-terminated string into the arena.
270+
*
271+
* @arena: a Pointer to the arena. Must not be NULL.
272+
* @str: NULL-terminated input string to duplicate. Must not be NULL.
273+
*
274+
* Return: Pointer to the duplicated string stored in the arena.
275+
*/
276+
char *arena_strdup(arena_t *arena, char *str)
277+
{
278+
int n = strlen(str);
279+
char *dup = arena_alloc(arena, n + 1);
280+
memcpy(dup, str, n);
281+
dup[n] = '\0';
282+
return dup;
283+
}
284+
285+
/**
286+
* arena_memdup() - Duplicate a block of memory into the arena.
287+
* Allocates size bytes within the arena and copies data from the input pointer.
288+
*
289+
* @arena: a Pointer to the arena. Must not be NULL.
290+
* @data: data Pointer to the source memory. Must not be NULL.
291+
* @size: size Number of bytes to copy. Must be non-negative.
292+
*
293+
* Return: The pointer to the duplicated memory stored in the arena.
294+
*/
295+
void *arena_memdup(arena_t *arena, void *data, int size)
296+
{
297+
return memcpy(arena_alloc(arena, size), data, size);
185298
}
186299

187300
/**
@@ -194,8 +307,7 @@ void arena_free(arena_t *arena)
194307

195308
while (block) {
196309
next = block->next;
197-
free(block->memory);
198-
free(block);
310+
arena_block_free(block);
199311
block = next;
200312
}
201313

0 commit comments

Comments
 (0)