Skip to content

Commit fe1de6d

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 fe1de6d

File tree

1 file changed

+123
-35
lines changed

1 file changed

+123
-35
lines changed

src/globals.c

Lines changed: 123 additions & 35 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,14 +98,14 @@ 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");
101+
printf("Failed to allocate memory for arena block structure\n");
103102
exit(1);
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);
111110
exit(1);
112111
}
@@ -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+
exit(1);
141+
}
129142
arena->head = arena_block_create(initial_capacity);
130143
return arena;
131144
}
@@ -141,47 +154,123 @@ 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;
146-
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;
157+
if (size <= 0) {
158+
printf("arena_alloc: size must be positive");
159+
exit(1);
156160
}
157161

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);
162+
/* Align to PTR_SIZE bytes */
163+
size = (size + PTR_SIZE - 1) & ~(PTR_SIZE - 1);
163164

164-
if (!new_block)
165-
return NULL;
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;
172+
}
166173

167-
block->next = new_block;
168-
ptr = new_block->memory + new_block->offset;
169-
new_block->offset += size;
174+
void *ptr = arena->head->memory + arena->head->offset;
175+
arena->head->offset += size;
170176
return ptr;
171177
}
172178

173179
/**
174-
* arena_reset() - Resets the given arena by resetting all blocks' offset to 0.
175-
* @arena: The arena to reset. Must not be NULL.
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.
176189
*/
177-
void arena_reset(arena_t *arena)
190+
void *arena_calloc(arena_t *arena, int n, int size)
178191
{
179-
arena_block_t *block = arena->head;
192+
int total = n * size;
193+
void *ptr = arena_alloc(arena, total);
180194

181-
while (block) {
182-
block->offset = 0;
183-
block = block->next;
195+
int *w_ptr = ptr;
196+
int w_count = total >> 2;
197+
int b_index = w_count << 2;
198+
199+
for (int i = 0; i < w_count; ++i)
200+
w_ptr[i] = 0;
201+
202+
char *b_ptr = ptr;
203+
while (b_index < total)
204+
b_ptr[b_index++] = 0;
205+
206+
return ptr;
207+
}
208+
209+
/**
210+
* arena_realloc() - Reallocate a previously allocated region within the arena
211+
* to a different size.
212+
*
213+
* If existing region is the most recent allocation in the current block
214+
* and there is enough space to expand in place, simply extend the offset.
215+
* Otherwise, allocate a new region of the requested size and copy the old data.
216+
*
217+
* @arena: Pointer to the arena. Must not be NULL.
218+
* @oldptr: Pointer to the previously allocated memory in the arena.
219+
* @oldsz: Original size (in bytes) of that allocation.
220+
* @newsz: New desired size (in bytes).
221+
*
222+
* Return: Pointer to the reallocated (resized) memory region.
223+
*/
224+
void *arena_realloc(arena_t *arena, char *oldptr, int oldsz, int newsz)
225+
{
226+
/* No need to grow; existing pointer is sufficient. */
227+
if (newsz <= oldsz)
228+
return oldptr;
229+
230+
/* Check if oldptr is at the end of the current block's allocations */
231+
if (oldptr + oldsz == arena->head->memory + arena->head->offset &&
232+
arena->head->offset + (newsz - oldsz) <= arena->head->capacity) {
233+
/* Grow in place */
234+
arena->head->offset += (newsz - oldsz);
235+
return oldptr;
184236
}
237+
238+
/* Otherwise, allocate new region and copy */
239+
void *newptr = arena_alloc(arena, newsz);
240+
memcpy(newptr, oldptr, oldsz);
241+
return newptr;
242+
}
243+
244+
/**
245+
* arena_strdup() - Duplicate a NULL-terminated string into the arena.
246+
*
247+
* @arena: a Pointer to the arena. Must not be NULL.
248+
* @str: NULL-terminated input string to duplicate. Must not be NULL.
249+
*
250+
* Return: Pointer to the duplicated string stored in the arena.
251+
*/
252+
char *arena_strdup(arena_t *arena, char *str)
253+
{
254+
int n = strlen(str);
255+
char *dup = arena_alloc(arena, n + 1);
256+
memcpy(dup, str, n);
257+
dup[n] = '\0';
258+
return dup;
259+
}
260+
261+
/**
262+
* arena_memdup() - Duplicate a block of memory into the arena.
263+
* Allocates size bytes within the arena and copies data from the input pointer.
264+
*
265+
* @arena: a Pointer to the arena. Must not be NULL.
266+
* @data: data Pointer to the source memory. Must not be NULL.
267+
* @size: size Number of bytes to copy. Must be non-negative.
268+
*
269+
* Return: The pointer to the duplicated memory stored in the arena.
270+
*/
271+
void *arena_memdup(arena_t *arena, void *data, int size)
272+
{
273+
return memcpy(arena_alloc(arena, size), data, size);
185274
}
186275

187276
/**
@@ -194,8 +283,7 @@ void arena_free(arena_t *arena)
194283

195284
while (block) {
196285
next = block->next;
197-
free(block->memory);
198-
free(block);
286+
arena_block_free(block);
199287
block = next;
200288
}
201289

0 commit comments

Comments
 (0)