Skip to content

Commit 1b9adb6

Browse files
committed
Implement arena allocator to reduce allocation
In this patch, by introducing arena allocator, also known as regional allocator, and optimizing calloc byte buffer clearing algorithm, the compiler's memory usage, page fault occurrence frequency, and performance are significantly improved. The resident set size has been reduced up to 2/3. Arena allocator's introduction allows future development safely allocating structures without worrying their lifetime. This has already been implemented in SSA unit's "basic_block_t" allocation, which now doesn't require traversal to free up all connected detached basic blocks. In addition, calloc's byte buffer clearing algorithm has been changed into bulk clearing algorithm, which clears up 4 bytes at a time when requested byte buffer's size is large enough.
1 parent 6196ab1 commit 1b9adb6

File tree

8 files changed

+144
-70
lines changed

8 files changed

+144
-70
lines changed

lib/c.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,12 +629,27 @@ void *malloc(int size)
629629

630630
void *calloc(int n, int size)
631631
{
632-
char *p = malloc(n * size);
632+
int total = n * size, offset = 0;
633+
char *p = malloc(total);
633634

634635
if (!p)
635636
return NULL;
636-
for (int i = 0; i < n * size; i++)
637-
p[i] = 0;
637+
638+
while ((p + offset) & 3 && offset < total) {
639+
p[offset++] = 0;
640+
}
641+
642+
int *pi = p + offset;
643+
int num_words = (total - offset) >> 2;
644+
645+
for (int i = 0; i < num_words; i++)
646+
pi[i] = 0;
647+
648+
offset += num_words;
649+
650+
while (offset < total)
651+
p[offset++] = 0;
652+
638653
return p;
639654
}
640655

src/arm-codegen.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ void cfg_flatten()
156156

157157
for (ph2_ir_t *insn = bb->ph2_ir_list.head; insn;
158158
insn = insn->next) {
159-
flatten_ir = add_ph2_ir(OP_generic);
160-
memcpy(flatten_ir, insn, sizeof(ph2_ir_t));
159+
flatten_ir = add_existed_ph2_ir(insn);
161160

162161
if (insn->op == OP_return) {
163162
/* restore sp */
@@ -470,7 +469,7 @@ void code_generate()
470469
emit(__b(__AL, MAIN_BB->elf_offset - elf_code_idx));
471470

472471
for (int i = 0; i < ph2_ir_idx; i++) {
473-
ph2_ir = &PH2_IR[i];
472+
ph2_ir = PH2_IR_FLATTEN[i];
474473
emit_ph2_ir(ph2_ir);
475474
}
476475
}

src/defs.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
#define MAX_OPERAND_STACK_SIZE 32
4242
#define MAX_ANALYSIS_STACK_SIZE 750
4343

44+
/* Default capacities */
45+
#define DEFAULT_ARENA_SIZE 262144
46+
4447
#define ELF_START 0x10000
4548
#define PTR_SIZE 4
4649

@@ -62,6 +65,18 @@
6265
#define HOST_PTR_SIZE __SIZEOF_POINTER__
6366
#endif
6467

68+
/* Common data structures */
69+
typedef struct arena_block {
70+
char *memory;
71+
int capacity;
72+
int offset;
73+
struct arena_block *next;
74+
} arena_block_t;
75+
76+
typedef struct {
77+
arena_block_t *head;
78+
} arena_t;
79+
6580
/* builtin types */
6681
typedef enum {
6782
TYPE_void = 0,

src/globals.c

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ int global_ir_idx = 0;
3232
ph1_ir_t *PH1_IR;
3333
int ph1_ir_idx = 0;
3434

35-
ph2_ir_t *PH2_IR;
35+
arena_t *INSN_ARENA;
36+
37+
/* BB_ARENA is responsible for basic_block_t / ph2_ir_t allocation */
38+
arena_t *BB_ARENA;
39+
40+
ph2_ir_t **PH2_IR_FLATTEN;
3641
int ph2_ir_idx = 0;
3742

3843
label_lut_t *LABEL_LUT;
@@ -69,6 +74,87 @@ char *elf_symtab;
6974
char *elf_strtab;
7075
char *elf_section;
7176

77+
arena_block_t *arena_block_create(int capacity)
78+
{
79+
arena_block_t *block = malloc(sizeof(arena_block_t));
80+
81+
if (!block) {
82+
printf("Failed to allocate memory for arena block\n");
83+
exit(1);
84+
}
85+
86+
block->memory = calloc(capacity, sizeof(char));
87+
88+
if (!block->memory) {
89+
printf("Failed to allocate memory for arena block\n");
90+
free(block);
91+
exit(1);
92+
}
93+
94+
block->capacity = capacity;
95+
block->offset = 0;
96+
block->next = NULL;
97+
return block;
98+
}
99+
100+
arena_t *arena_init(int initial_capacity)
101+
{
102+
arena_t *arena = malloc(sizeof(arena_t));
103+
arena->head = arena_block_create(initial_capacity);
104+
return arena;
105+
}
106+
107+
void *arena_alloc(arena_t *arena, int size)
108+
{
109+
char *ptr;
110+
arena_block_t *block = arena->head;
111+
112+
while (block) {
113+
if (block->offset + size <= block->capacity) {
114+
ptr = block->memory + block->offset;
115+
block->offset += size;
116+
return ptr;
117+
}
118+
if (!block->next)
119+
break;
120+
block = block->next;
121+
}
122+
123+
/* If no space is available, create a new block
124+
* Allocate at least 1 KB or the requested size
125+
*/
126+
int new_capacity = size > DEFAULT_ARENA_SIZE ? size : DEFAULT_ARENA_SIZE;
127+
arena_block_t *new_block = arena_block_create(new_capacity);
128+
block->next = new_block;
129+
ptr = new_block->memory + new_block->offset;
130+
new_block->offset += size;
131+
return ptr;
132+
}
133+
134+
void arena_reset(arena_t *arena)
135+
{
136+
arena_block_t *block = arena->head;
137+
138+
while (block) {
139+
block->offset = 0;
140+
block = block->next;
141+
}
142+
}
143+
144+
void arena_free(arena_t *arena)
145+
{
146+
arena_block_t *block = arena->head, *next;
147+
148+
while (block) {
149+
next = block->next;
150+
free(block->memory);
151+
free(block);
152+
block = next;
153+
}
154+
155+
free(arena);
156+
}
157+
72158
/**
73159
* hashmap_hash_index() - hashses a string with FNV-1a hash function
74160
* and converts into usable hashmap index. The range of returned
@@ -312,11 +398,17 @@ ph1_ir_t *add_ph1_ir(opcode_t op)
312398
return ph1_ir;
313399
}
314400

401+
ph2_ir_t *add_existed_ph2_ir(ph2_ir_t *ph2_ir)
402+
{
403+
PH2_IR_FLATTEN[ph2_ir_idx++] = ph2_ir;
404+
return ph2_ir;
405+
}
406+
315407
ph2_ir_t *add_ph2_ir(opcode_t op)
316408
{
317-
ph2_ir_t *ph2_ir = &PH2_IR[ph2_ir_idx++];
409+
ph2_ir_t *ph2_ir = arena_alloc(BB_ARENA, sizeof(ph2_ir_t));
318410
ph2_ir->op = op;
319-
return ph2_ir;
411+
return add_existed_ph2_ir(ph2_ir);
320412
}
321413

322414
void set_var_liveout(var_t *var, int end)
@@ -579,7 +671,7 @@ fn_t *add_fn()
579671
/* Create a basic block and set the scope of variables to 'parent' block */
580672
basic_block_t *bb_create(block_t *parent)
581673
{
582-
basic_block_t *bb = calloc(1, sizeof(basic_block_t));
674+
basic_block_t *bb = arena_alloc(BB_ARENA, sizeof(basic_block_t));
583675

584676
for (int i = 0; i < MAX_BB_PRED; i++) {
585677
bb->prev[i].bb = NULL;
@@ -691,7 +783,7 @@ void add_insn(block_t *block,
691783

692784
bb->scope = block;
693785

694-
insn_t *n = calloc(1, sizeof(insn_t));
786+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
695787
n->opcode = op;
696788
n->rd = rd;
697789
n->rs1 = rs1;
@@ -725,7 +817,9 @@ void global_init()
725817
TYPES = malloc(MAX_TYPES * sizeof(type_t));
726818
GLOBAL_IR = malloc(MAX_GLOBAL_IR * sizeof(ph1_ir_t));
727819
PH1_IR = malloc(MAX_IR_INSTR * sizeof(ph1_ir_t));
728-
PH2_IR = malloc(MAX_IR_INSTR * sizeof(ph2_ir_t));
820+
INSN_ARENA = arena_init(DEFAULT_ARENA_SIZE);
821+
BB_ARENA = arena_init(DEFAULT_ARENA_SIZE);
822+
PH2_IR_FLATTEN = malloc(MAX_IR_INSTR * sizeof(ph2_ir_t));
729823
LABEL_LUT = malloc(MAX_LABEL * sizeof(label_lut_t));
730824
SOURCE = malloc(MAX_SOURCE);
731825
ALIASES = malloc(MAX_ALIASES * sizeof(alias_t));
@@ -755,7 +849,9 @@ void global_release()
755849
free(TYPES);
756850
free(GLOBAL_IR);
757851
free(PH1_IR);
758-
free(PH2_IR);
852+
arena_free(INSN_ARENA);
853+
arena_free(BB_ARENA);
854+
free(PH2_IR_FLATTEN);
759855
free(LABEL_LUT);
760856
free(SOURCE);
761857
free(ALIASES);

src/main.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ int main(int argc, char *argv[])
115115
elf_generate(out);
116116

117117
/* release allocated objects */
118-
ssa_release();
119118
global_release();
120119

121120
exit(0);

src/reg-alloc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void refresh(basic_block_t *bb, insn_t *insn)
4949

5050
ph2_ir_t *bb_add_ph2_ir(basic_block_t *bb, opcode_t op)
5151
{
52-
ph2_ir_t *n = calloc(1, sizeof(ph2_ir_t));
52+
ph2_ir_t *n = arena_alloc(BB_ARENA, sizeof(ph2_ir_t));
5353
n->op = op;
5454

5555
if (!bb->ph2_ir_list.head)
@@ -640,7 +640,7 @@ void reg_alloc()
640640
void dump_ph2_ir()
641641
{
642642
for (int i = 0; i < ph2_ir_idx; i++) {
643-
ph2_ir_t *ph2_ir = &PH2_IR[i];
643+
ph2_ir_t *ph2_ir = PH2_IR_FLATTEN[i];
644644

645645
int rd = ph2_ir->dest + 48;
646646
int rs1 = ph2_ir->src0 + 48;

src/riscv-codegen.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ void cfg_flatten()
128128

129129
for (ph2_ir_t *insn = bb->ph2_ir_list.head; insn;
130130
insn = insn->next) {
131-
flatten_ir = add_ph2_ir(OP_generic);
132-
memcpy(flatten_ir, insn, sizeof(ph2_ir_t));
131+
flatten_ir = add_existed_ph2_ir(insn);
133132

134133
if (insn->op == OP_return) {
135134
/* restore sp */
@@ -446,7 +445,7 @@ void code_generate()
446445
emit(__jal(__zero, MAIN_BB->elf_offset - elf_code_idx));
447446

448447
for (int i = 0; i < ph2_ir_idx; i++) {
449-
ph2_ir = &PH2_IR[i];
448+
ph2_ir = PH2_IR_FLATTEN[i];
450449
emit_ph2_ir(ph2_ir);
451450
}
452451
}

src/ssa.c

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ bool insert_phi_insn(basic_block_t *bb, var_t *var)
588588
return false;
589589

590590
insn_t *head = bb->insn_list.head;
591-
insn_t *n = calloc(1, sizeof(insn_t));
591+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
592592
n->opcode = OP_phi;
593593
n->rd = var;
594594
n->rs1 = var;
@@ -810,7 +810,7 @@ void solve_phi_params()
810810

811811
void append_unwound_phi_insn(basic_block_t *bb, var_t *dest, var_t *rs)
812812
{
813-
insn_t *n = calloc(1, sizeof(insn_t));
813+
insn_t *n = arena_alloc(INSN_ARENA, sizeof(insn_t));
814814
n->opcode = OP_unwound_phi;
815815
n->rd = dest;
816816
n->rs1 = rs;
@@ -1770,52 +1770,3 @@ void liveness_analysis()
17701770
} while (changed);
17711771
}
17721772
}
1773-
1774-
void bb_release(fn_t *fn, basic_block_t *bb)
1775-
{
1776-
UNUSED(fn);
1777-
1778-
insn_t *insn = bb->insn_list.head;
1779-
insn_t *next_insn;
1780-
while (insn) {
1781-
next_insn = insn->next;
1782-
free(insn);
1783-
insn = next_insn;
1784-
}
1785-
1786-
/* disconnect all predecessors */
1787-
for (int i = 0; i < MAX_BB_PRED; i++) {
1788-
if (!bb->prev[i].bb)
1789-
continue;
1790-
switch (bb->prev[i].type) {
1791-
case NEXT:
1792-
bb->prev[i].bb->next = NULL;
1793-
break;
1794-
case THEN:
1795-
bb->prev[i].bb->then_ = NULL;
1796-
break;
1797-
case ELSE:
1798-
bb->prev[i].bb->else_ = NULL;
1799-
break;
1800-
default:
1801-
abort();
1802-
}
1803-
1804-
bb->prev[i].bb = NULL;
1805-
}
1806-
free(bb);
1807-
}
1808-
1809-
void ssa_release()
1810-
{
1811-
bb_traversal_args_t *args = calloc(1, sizeof(bb_traversal_args_t));
1812-
for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
1813-
args->fn = fn;
1814-
args->bb = fn->bbs;
1815-
1816-
fn->visited++;
1817-
args->postorder_cb = bb_release;
1818-
bb_forward_traversal(args);
1819-
}
1820-
free(args);
1821-
}

0 commit comments

Comments
 (0)