Browse Source

Implement custom temporary allocator using ring buffer

gingerBill 4 years ago
parent
commit
0d6f5cec37
7 changed files with 101 additions and 84 deletions
  1. 0 1
      src/check_decl.cpp
  2. 0 9
      src/check_expr.cpp
  3. 0 5
      src/check_stmt.cpp
  4. 94 36
      src/common.cpp
  5. 0 2
      src/ir_print.cpp
  6. 0 24
      src/llvm_backend.cpp
  7. 7 7
      src/main.cpp

+ 0 - 1
src/check_decl.cpp

@@ -121,7 +121,6 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar
 
 	// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
 	// an extra allocation
-	SCOPED_TEMPORARY_BLOCK();
 	auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
 	check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
 

+ 0 - 9
src/check_expr.cpp

@@ -1832,7 +1832,6 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
 	}
 
 
-	SCOPED_TEMPORARY_BLOCK();
 	gbString err_str = nullptr;
 
 	if (check_is_assignable_to(c, x, y->type) ||
@@ -2974,8 +2973,6 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
 
 	case Type_Union:
 		if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
-			SCOPED_TEMPORARY_BLOCK();
-
 			isize count = t->Union.variants.count;
 			ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count);
 			isize valid_count = 0;
@@ -6536,8 +6533,6 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
 	bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
 	CallArgumentError err = CallArgumentError_None;
 
-	SCOPED_TEMPORARY_BLOCK();
-
 	isize param_count = pt->param_count;
 	bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count);
 	auto ordered_operands = array_make<Operand>(temporary_allocator(), param_count);
@@ -7385,8 +7380,6 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 		ordered_operands = array_make<Operand>(permanent_allocator(), param_count);
 		array_copy(&ordered_operands, operands, 0);
 	} else {
-		SCOPED_TEMPORARY_BLOCK();
-
 		bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count);
 
 		// LEAK(bill)
@@ -8507,8 +8500,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 			}
 
 			if (cl->elems[0]->kind == Ast_FieldValue) {
-				SCOPED_TEMPORARY_BLOCK();
-
 				bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count);
 
 				for_array(i, cl->elems) {

+ 0 - 5
src/check_stmt.cpp

@@ -640,8 +640,6 @@ void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Oper
 	HashKey key = hash_exact_value(operand.value);
 	TypeAndToken *found = map_get(seen, key);
 	if (found != nullptr) {
-		SCOPED_TEMPORARY_BLOCK();
-
 		isize count = multi_map_count(seen, key);
 		TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count);
 
@@ -1026,7 +1024,6 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 		GB_ASSERT(is_type_enum(et));
 		auto fields = et->Enum.fields;
 
-		SCOPED_TEMPORARY_BLOCK();
 		auto unhandled = array_make<Entity *>(temporary_allocator(), 0, fields.count);
 
 		for_array(i, fields) {
@@ -1266,7 +1263,6 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
 		GB_ASSERT(is_type_union(ut));
 		auto variants = ut->Union.variants;
 
-		SCOPED_TEMPORARY_BLOCK();
 		auto unhandled = array_make<Type *>(temporary_allocator(), 0, variants.count);
 
 		for_array(i, variants) {
@@ -1434,7 +1430,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
 				return;
 			}
 
-			SCOPED_TEMPORARY_BLOCK();
 
 			// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
 			// an extra allocation

+ 94 - 36
src/common.cpp

@@ -56,6 +56,14 @@ gb_inline isize align_formula_isize(isize size, isize align) {
 	}
 	return size;
 }
+gb_inline void *align_formula_ptr(void *ptr, isize align) {
+	if (align > 0) {
+		uintptr result = (cast(uintptr)ptr) + align-1;
+		return (void *)(result - result%align);
+	}
+	return ptr;
+}
+
 
 GB_ALLOCATOR_PROC(heap_allocator_proc);
 
@@ -380,6 +388,9 @@ typedef struct Arena {
 #define ARENA_MIN_ALIGNMENT 16
 #define ARENA_DEFAULT_BLOCK_SIZE (8*1024*1024)
 
+
+gb_global Arena permanent_arena = {};
+
 void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAULT_BLOCK_SIZE) {
 	arena->backing = backing;
 	arena->block_size = block_size;
@@ -491,51 +502,98 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
 	return ptr;
 }
 
-struct SCOPED_TEMP_ARENA_MEMORY {
-	Arena *arena;
-	u8 *   ptr;
-	u8 *   end;
-	u8 *   prev;
-	isize  total_used;
-	isize  block_count;
-
-	SCOPED_TEMP_ARENA_MEMORY(Arena *the_arena) {
-		GB_ASSERT(!the_arena->use_mutex);
-		arena       = the_arena;
-		ptr         = arena->ptr;
-		end         = arena->end;
-		prev        = arena->prev;
-		total_used  = arena->total_used;
-		block_count = arena->blocks.count;
-	}
-	~SCOPED_TEMP_ARENA_MEMORY() {
-		if (arena->blocks.count != block_count) {
-			for (isize i = block_count; i < arena->blocks.count; i++) {
-				gb_free(arena->backing, arena->blocks[i]);
-			}
-			arena->blocks.count = block_count;
-		}
-		arena->ptr        = ptr;
-		arena->end        = end;
-		arena->prev       = prev;
-		arena->total_used = total_used;
-	}
+
+gbAllocator permanent_allocator() {
+	return arena_allocator(&permanent_arena);
+	// return heap_allocator();
+}
+
+
+
+struct Temp_Allocator {
+	u8 *data;
+	isize len;
+	isize curr_offset;
+	gbAllocator backup_allocator;
+	Array<void *> leaked_allocations;
 };
 
+gb_global Temp_Allocator temporary_allocator_data = {};
 
+void temp_allocator_init(Temp_Allocator *s, isize size) {
+	s->backup_allocator = heap_allocator();
+	s->data = cast(u8 *)gb_alloc_align(s->backup_allocator, size, 16);
+	s->curr_offset = 0;
+	s->leaked_allocations.allocator = s->backup_allocator;
+}
 
+void *temp_allocator_alloc(Temp_Allocator *s, isize size, isize alignment) {
+	size = align_formula_isize(size, alignment);
+	if (s->curr_offset+size <= s->len) {
+		u8 *start = s->data;
+		u8 *ptr = start + s->curr_offset;
+		ptr = cast(u8 *)align_formula_ptr(ptr, alignment);
+		// assume memory is zero
+
+		isize offset = ptr - start;
+		s->curr_offset = offset + size;
+		return ptr;
+	} else if (size <= s->len) {
+		u8 *start = s->data;
+		u8 *ptr = cast(u8 *)align_formula_ptr(start, alignment);
+		// assume memory is zero
+
+		isize offset = ptr - start;
+		s->curr_offset = offset + size;
+		return ptr;
+	}
 
-gb_global Arena permanent_arena = {};
-gb_global Arena temporary_arena = {};
+	void *ptr = gb_alloc_align(s->backup_allocator, size, alignment);
+	array_add(&s->leaked_allocations, ptr);
+	return ptr;
+}
 
-gbAllocator permanent_allocator() {
-	return arena_allocator(&permanent_arena);
+void temp_allocator_free_all(Temp_Allocator *s) {
+	s->curr_offset = 0;
+	for_array(i, s->leaked_allocations) {
+		gb_free(s->backup_allocator, s->leaked_allocations[i]);
+	}
+	array_clear(&s->leaked_allocations);
+	gb_zero_size(s->data, s->len);
 }
-gbAllocator temporary_allocator() {
-	return arena_allocator(&temporary_arena);
+
+GB_ALLOCATOR_PROC(temp_allocator_proc) {
+	void *ptr = nullptr;
+	Temp_Allocator *s = cast(Temp_Allocator *)allocator_data;
+	GB_ASSERT_NOT_NULL(s);
+
+	switch (type) {
+	case gbAllocation_Alloc:
+		return temp_allocator_alloc(s, size, alignment);
+	case gbAllocation_Free:
+		break;
+	case gbAllocation_Resize:
+		if (size == 0) {
+			ptr = nullptr;
+		} else if (size <= old_size) {
+			ptr = old_memory;
+		} else {
+			ptr = temp_allocator_alloc(s, size, alignment);
+			gb_memmove(ptr, old_memory, old_size);
+		}
+		break;
+	case gbAllocation_FreeAll:
+		temp_allocator_free_all(s);
+		break;
+	}
+
+	return ptr;
 }
 
-#define SCOPED_TEMPORARY_BLOCK() auto GB_DEFER_3(_SCOPED_TEMPORARY_BLOCK_) = SCOPED_TEMP_ARENA_MEMORY(&temporary_arena)
+
+gbAllocator temporary_allocator() {
+	return {temp_allocator_proc, &temporary_allocator_data};
+}
 
 
 

+ 0 - 2
src/ir_print.cpp

@@ -76,8 +76,6 @@ void ir_write_u64(irFileBuffer *f, u64 i) {
 }
 void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) {
 	if (x.len == 2) {
-		SCOPED_TEMPORARY_BLOCK();
-
 		u64 words[2] = {};
 		BigInt y = x;
 		if (swap_endian) {

+ 0 - 24
src/llvm_backend.cpp

@@ -781,8 +781,6 @@ void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant
 
 
 void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) {
-	SCOPED_TEMPORARY_BLOCK();
-
 	unsigned field_count = LLVMCountStructElementTypes(src);
 	LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 	LLVMGetStructElementTypes(src, fields);
@@ -1279,8 +1277,6 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			m->internal_type_level += 1;
 			defer (m->internal_type_level -= 1);
 
-			SCOPED_TEMPORARY_BLOCK();
-
 			unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 
@@ -1341,8 +1337,6 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		if (type->Tuple.variables.count == 1) {
 			return lb_type(m, type->Tuple.variables[0]->type);
 		} else {
-			SCOPED_TEMPORARY_BLOCK();
-
 			unsigned field_count = cast(unsigned)(type->Tuple.variables.count);
 			LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
 
@@ -1442,8 +1436,6 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				extra_param_count += 1;
 			}
 
-			SCOPED_TEMPORARY_BLOCK();
-
 			isize param_count = type->Proc.abi_compat_params.count + extra_param_count;
 			auto param_types = array_make<LLVMTypeRef>(temporary_allocator(), 0, param_count);
 
@@ -1490,8 +1482,6 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 		{
 			LLVMTypeRef internal_type = nullptr;
 			{
-				SCOPED_TEMPORARY_BLOCK();
-
 				GB_ASSERT(type->BitField.fields.count == type->BitField.sizes.count);
 				unsigned field_count = cast(unsigned)type->BitField.fields.count;
 				LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count);
@@ -5288,8 +5278,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				return lb_const_nil(m, original_type);
 			}
 			if (cl->elems[0]->kind == Ast_FieldValue) {
-				SCOPED_TEMPORARY_BLOCK();
-
 				// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
 				LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count);
 
@@ -5348,7 +5336,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			} else {
 				GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
 
-				SCOPED_TEMPORARY_BLOCK();
 				LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count);
 
 				for (isize i = 0; i < elem_count; i++) {
@@ -5371,7 +5358,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				return lb_const_nil(m, original_type);
 			}
 			if (cl->elems[0]->kind == Ast_FieldValue) {
-				SCOPED_TEMPORARY_BLOCK();
 				// TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand
 				LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count);
 
@@ -5434,7 +5420,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			} else {
 				GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count);
 
-				SCOPED_TEMPORARY_BLOCK();
 				LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count);
 
 				for (isize i = 0; i < elem_count; i++) {
@@ -5459,8 +5444,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 			}
 			GB_ASSERT(elem_type_can_be_constant(elem_type));
 
-			SCOPED_TEMPORARY_BLOCK();
-
 			isize total_elem_count = type->SimdVector.count;
 			LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, total_elem_count);
 
@@ -5487,13 +5470,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
 				offset = 1;
 			}
 
-			SCOPED_TEMPORARY_BLOCK();
-
 			isize value_count = type->Struct.fields.count + offset;
 			LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count);
 			bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count);
 
-
 			if (cl->elems.count > 0) {
 				if (cl->elems[0]->kind == Ast_FieldValue) {
 					isize elem_count = cl->elems.count;
@@ -10896,7 +10876,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			if (cl->elems.count > 0) {
 				lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
 
-				SCOPED_TEMPORARY_BLOCK();
 				auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
 
 				// NOTE(bill): Separate value, gep, store into their own chunks
@@ -10996,7 +10975,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 			if (cl->elems.count > 0) {
 				lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
 
-				SCOPED_TEMPORARY_BLOCK();
 				auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
 
 				// NOTE(bill): Separate value, gep, store into their own chunks
@@ -11105,7 +11083,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 				lbValue data = lb_slice_elem(p, slice);
 
-				SCOPED_TEMPORARY_BLOCK();
 				auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
 
 				for_array(i, cl->elems) {
@@ -11954,7 +11931,6 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 					                                        str_lit("$enum_values"), cast(i64)entry_index);
 
 
-					SCOPED_TEMPORARY_BLOCK();
 					LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count);
 					LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count);
 

+ 7 - 7
src/main.cpp

@@ -1644,7 +1644,7 @@ int main(int arg_count, char const **arg_ptr) {
 	defer (timings_destroy(timings));
 
 	arena_init(&permanent_arena, heap_allocator());
-	arena_init(&temporary_arena, heap_allocator());
+	temp_allocator_init(&temporary_allocator_data, 16*1024*1024);
 	arena_init(&global_ast_arena, heap_allocator());
 	permanent_arena.use_mutex = true;
 
@@ -1799,7 +1799,7 @@ int main(int arg_count, char const **arg_ptr) {
 		return 1;
 	}
 
-	arena_free_all(&temporary_arena);
+	temp_allocator_free_all(&temporary_allocator_data);
 
 	if (build_context.generate_docs) {
 		// generate_documentation(&parser);
@@ -1818,7 +1818,7 @@ int main(int arg_count, char const **arg_ptr) {
 		check_parsed_files(&checker);
 	}
 
-	arena_free_all(&temporary_arena);
+	temp_allocator_free_all(&temporary_allocator_data);
 
 	if (build_context.no_output_files) {
 		if (build_context.query_data_set_settings.ok) {
@@ -1849,7 +1849,7 @@ int main(int arg_count, char const **arg_ptr) {
 		}
 		lb_generate_code(&gen);
 
-		arena_free_all(&temporary_arena);
+		temp_allocator_free_all(&temporary_allocator_data);
 
 		switch (build_context.build_mode) {
 		case BuildMode_Executable:
@@ -1928,17 +1928,17 @@ int main(int arg_count, char const **arg_ptr) {
 		timings_start_section(timings, str_lit("llvm ir gen"));
 		ir_gen_tree(&ir_gen);
 
-		arena_free_all(&temporary_arena);
+		temp_allocator_free_all(&temporary_allocator_data);
 
 		timings_start_section(timings, str_lit("llvm ir opt tree"));
 		ir_opt_tree(&ir_gen);
 
-		arena_free_all(&temporary_arena);
+		temp_allocator_free_all(&temporary_allocator_data);
 
 		timings_start_section(timings, str_lit("llvm ir print"));
 		print_llvm_ir(&ir_gen);
 
-		arena_free_all(&temporary_arena);
+		temp_allocator_free_all(&temporary_allocator_data);
 
 
 		String output_name = ir_gen.output_name;