瀏覽代碼

Minimize more thread contention

gingerBill 1 天之前
父節點
當前提交
a36a8722dc
共有 10 個文件被更改,包括 74 次插入58 次删除
  1. 1 1
      src/build_settings.cpp
  2. 2 2
      src/check_decl.cpp
  3. 7 9
      src/check_expr.cpp
  4. 3 2
      src/check_stmt.cpp
  5. 5 4
      src/check_type.cpp
  6. 31 27
      src/checker.cpp
  7. 8 7
      src/checker.hpp
  8. 1 1
      src/entity.cpp
  9. 11 0
      src/error.cpp
  10. 5 5
      src/threading.cpp

+ 1 - 1
src/build_settings.cpp

@@ -1163,7 +1163,7 @@ gb_internal String internal_odin_root_dir(void) {
 		return global_module_path;
 	}
 
-	auto path_buf = array_make<char>(heap_allocator(), 300);
+	auto path_buf = array_make<char>(temporary_allocator(), 300);
 	defer (array_free(&path_buf));
 
 	len = 0;

+ 2 - 2
src/check_decl.cpp

@@ -1981,9 +1981,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
 
 	ast_node(bs, BlockStmt, body);
 
+	TEMPORARY_ALLOCATOR_GUARD();
 	Array<ProcUsingVar> using_entities = {};
-	using_entities.allocator = heap_allocator();
-	defer (array_free(&using_entities));
+	using_entities.allocator = temporary_allocator();
 
 	{
 		if (type->Proc.param_count > 0) {

+ 7 - 9
src/check_expr.cpp

@@ -7516,11 +7516,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
 		return check_call_arguments_proc_group(c, operand, call);
 	}
 
-	auto positional_operands = array_make<Operand>(heap_allocator(), 0, positional_args.count);
-	auto named_operands      = array_make<Operand>(heap_allocator(), 0, 0);
+	TEMPORARY_ALLOCATOR_GUARD();
 
-	defer (array_free(&positional_operands));
-	defer (array_free(&named_operands));
+	auto positional_operands = array_make<Operand>(temporary_allocator(), 0, positional_args.count);
+	auto named_operands      = array_make<Operand>(temporary_allocator(), 0, 0);
 
 	if (positional_args.count > 0) {
 		Entity **lhs =  nullptr;
@@ -7623,11 +7622,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
 	{
 		// NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves
 		auto prev_type_path = c->type_path;
-		c->type_path = new_checker_type_path();
-		defer ({
-			destroy_checker_type_path(c->type_path);
-			c->type_path = prev_type_path;
-		});
+		TEMPORARY_ALLOCATOR_GUARD();
+
+		c->type_path = new_checker_type_path(temporary_allocator());
+		defer (c->type_path = prev_type_path);
 
 		if (is_call_expr_field_value(ce)) {
 			named_fields = true;

+ 3 - 2
src/check_stmt.cpp

@@ -2567,8 +2567,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
 		result_count = proc_type->Proc.results->Tuple.variables.count;
 	}
 
-	auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
-	defer (array_free(&operands));
+	TEMPORARY_ALLOCATOR_GUARD();
+
+	auto operands = array_make<Operand>(temporary_allocator(), 0, 2*rs->results.count);
 
 	check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
 

+ 5 - 4
src/check_type.cpp

@@ -3512,8 +3512,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
 
 	case_ast_node(pt, PointerType, e);
 		CheckerContext c = *ctx;
-		c.type_path = new_checker_type_path();
-		defer (destroy_checker_type_path(c.type_path));
+
+		TEMPORARY_ALLOCATOR_GUARD();
+		c.type_path = new_checker_type_path(temporary_allocator());
 
 		Type *elem = t_invalid;
 		Operand o = {};
@@ -3747,8 +3748,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
 
 gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
 	CheckerContext c = *ctx;
-	c.type_path = new_checker_type_path();
-	defer (destroy_checker_type_path(c.type_path));
+	TEMPORARY_ALLOCATOR_GUARD();
+	c.type_path = new_checker_type_path(temporary_allocator());
 
 	return check_type_expr(&c, e, nullptr);
 }

+ 31 - 27
src/checker.cpp

@@ -1441,7 +1441,8 @@ gb_internal void init_checker_info(CheckerInfo *i) {
 	map_init(&i->objc_method_implementations);
 
 	string_map_init(&i->load_file_cache);
-	array_init(&i->all_procedures, heap_allocator());
+	array_init(&i->all_procedures, a);
+	mpsc_init(&i->all_procedures_queue, a);
 
 	mpsc_init(&i->entity_queue, a); // 1<<20);
 	mpsc_init(&i->definition_queue, a); //); // 1<<20);
@@ -1475,6 +1476,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
 	array_free(&i->required_foreign_imports_through_force);
 	array_free(&i->defineables);
 
+	array_free(&i->all_procedures);
+
+	mpsc_destroy(&i->all_procedures_queue);
+
 	mpsc_destroy(&i->entity_queue);
 	mpsc_destroy(&i->definition_queue);
 	mpsc_destroy(&i->required_global_variable_queue);
@@ -1502,12 +1507,12 @@ gb_internal CheckerContext make_checker_context(Checker *c) {
 	ctx.scope     = builtin_pkg->scope;
 	ctx.pkg       = builtin_pkg;
 
-	ctx.type_path = new_checker_type_path();
+	ctx.type_path = new_checker_type_path(heap_allocator());
 	ctx.type_level = 0;
 	return ctx;
 }
 gb_internal void destroy_checker_context(CheckerContext *ctx) {
-	destroy_checker_type_path(ctx->type_path);
+	destroy_checker_type_path(ctx->type_path, heap_allocator());
 }
 
 gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) {
@@ -1758,7 +1763,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode,
 	check_set_expr_info(c, expr, mode, type, value);
 }
 
-gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) {
+gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex) {
 	if (expr == nullptr) {
 		return;
 	}
@@ -1776,7 +1781,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
 		mutex = &ctx->pkg->type_and_value_mutex;
 	}
 
-	mutex_lock(mutex);
+	if (use_mutex) mutex_lock(mutex);
 	Ast *prev_expr = nullptr;
 	while (prev_expr != expr) {
 		prev_expr = expr;
@@ -1801,7 +1806,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
 			break;
 		};
 	}
-	mutex_unlock(mutex);
+	if (use_mutex) mutex_unlock(mutex);
 }
 
 gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) {
@@ -2345,11 +2350,9 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) {
 	}
 
 	if (DEBUG_CHECK_ALL_PROCEDURES) {
-		MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) {
-			GB_ASSERT(info != nullptr);
-			GB_ASSERT(info->decl != nullptr);
-			array_add(&c->info.all_procedures, info);
-		}
+		GB_ASSERT(info != nullptr);
+		GB_ASSERT(info->decl != nullptr);
+		mpsc_enqueue(&c->info.all_procedures_queue, info);
 	}
 }
 
@@ -3195,19 +3198,17 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String
 	return e->type;
 }
 
-gb_internal CheckerTypePath *new_checker_type_path() {
-	gbAllocator a = heap_allocator();
-	auto *tp = gb_alloc_item(a, CheckerTypePath);
-	array_init(tp, a, 0, 16);
+gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) {
+	auto *tp = gb_alloc_item(allocator, CheckerTypePath);
+	array_init(tp, allocator, 0, 16);
 	return tp;
 }
 
-gb_internal void destroy_checker_type_path(CheckerTypePath *tp) {
+gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) {
 	array_free(tp);
-	gb_free(heap_allocator(), tp);
+	gb_free(allocator, tp);
 }
 
-
 gb_internal void check_type_path_push(CheckerContext *c, Entity *e) {
 	GB_ASSERT(c->type_path != nullptr);
 	GB_ASSERT(e != nullptr);
@@ -5283,9 +5284,10 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
 	GB_ASSERT(scope->flags&ScopeFlag_Pkg);
 
 
-	if (ptr_set_update(&parent_scope->imported, scope)) {
-		// error(token, "Multiple import of the same file within this scope");
-	}
+	ptr_set_add(&parent_scope->imported, scope);
+	// if (ptr_set_update(&parent_scope->imported, scope)) {
+	// 	// error(token, "Multiple import of the same file within this scope");
+	// }
 
 	String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
 	if (is_blank_ident(import_name)) {
@@ -6041,10 +6043,10 @@ gb_internal void calculate_global_init_order(Checker *c) {
 	CheckerInfo *info = &c->info;
 
 	TIME_SECTION("calculate_global_init_order: generate entity dependency graph");
-	Arena *arena = get_arena(ThreadArena_Temporary);
-	ArenaTempGuard arena_guard(arena);
+	Arena *temporary_arena = get_arena(ThreadArena_Temporary);
+	ArenaTempGuard temporary_arena_guard(temporary_arena);
 
-	Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, arena);
+	Array<EntityGraphNode *> dep_graph = generate_entity_dependency_graph(info, temporary_arena);
 
 	TIME_SECTION("calculate_global_init_order: priority queue create");
 	// NOTE(bill): Priority queue
@@ -6321,8 +6323,9 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) {
 	defer (map_destroy(&untyped));
 
 
-	for_array(i, c->info.all_procedures) {
-		ProcInfo *pi = c->info.all_procedures[i];
+	array_reserve(&c->info.all_procedures, c->info.all_procedures_queue.count.load());
+
+	for (ProcInfo *pi = nullptr; mpsc_dequeue(&c->info.all_procedures_queue, &pi); /**/) {
 		GB_ASSERT(pi != nullptr);
 		GB_ASSERT(pi->decl != nullptr);
 		Entity *e = pi->decl->entity;
@@ -6337,6 +6340,8 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) {
 				consume_proc_info(c, pi, &untyped);
 			}
 		}
+
+		array_add(&c->info.all_procedures, pi);
 	}
 }
 
@@ -7412,7 +7417,6 @@ gb_internal void check_parsed_files(Checker *c) {
 
 
 	TIME_SECTION("add untyped expression values");
-	// Add untyped expression values
 	for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) {
 		GB_ASSERT(u.expr != nullptr && u.info != nullptr);
 		if (is_type_typed(u.info->type)) {

+ 8 - 7
src/checker.hpp

@@ -309,11 +309,12 @@ struct EntityGraphNode;
 typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
 
 struct EntityGraphNode {
-	Entity *     entity; // Procedure, Variable, Constant
+	Entity *entity; // Procedure, Variable, Constant
+
 	EntityGraphNodeSet pred;
 	EntityGraphNodeSet succ;
-	isize        index; // Index in array/queue
-	isize        dep_count;
+	isize index; // Index in array/queue
+	isize dep_count;
 };
 
 
@@ -516,7 +517,7 @@ struct CheckerInfo {
 	BlockingMutex load_file_mutex;
 	StringMap<LoadFileCache *> load_file_cache;
 
-	BlockingMutex all_procedures_mutex;
+	MPSCQueue<ProcInfo *> all_procedures_queue;
 	Array<ProcInfo *> all_procedures;
 
 	BlockingMutex instrumentation_mutex;
@@ -629,7 +630,7 @@ gb_internal void    scope_lookup_parent (Scope *s, String const &name, Scope **s
 gb_internal Entity *scope_insert (Scope *s, Entity *entity);
 
 
-gb_internal void      add_type_and_value      (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value);
+gb_internal void      add_type_and_value      (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true);
 gb_internal ExprInfo *check_get_expr_info     (CheckerContext *c, Ast *expr);
 gb_internal void      add_untyped             (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value);
 gb_internal void      add_entity_use          (CheckerContext *c, Ast *identifier, Entity *entity);
@@ -650,8 +651,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
 gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
 gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
 
-gb_internal CheckerTypePath *new_checker_type_path();
-gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
+gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator);
+gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator);
 
 gb_internal void    check_type_path_push(CheckerContext *c, Entity *e);
 gb_internal Entity *check_type_path_pop (CheckerContext *c);

+ 1 - 1
src/entity.cpp

@@ -348,7 +348,7 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ
 	entity->type   = type;
 	entity->id     = 1 + global_entity_id.fetch_add(1);
 	if (token.pos.file_id) {
-		entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id);
+		entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id);
 	}
 	return entity;
 }

+ 11 - 0
src/error.cpp

@@ -153,6 +153,17 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
 }
 
 
+// use AFTER PARSER
+gb_internal AstFile *thread_unsafe_get_ast_file_from_id(i32 index) {
+	GB_ASSERT(index >= 0);
+	AstFile *file = nullptr;
+	if (index < global_files.count) {
+		file = global_files[index];
+	}
+	return file;
+}
+
+
 
 // NOTE: defined in build_settings.cpp
 gb_internal bool global_warnings_as_errors(void);

+ 5 - 5
src/threading.cpp

@@ -448,9 +448,9 @@ gb_internal void semaphore_wait(Semaphore *s) {
 	}
 #endif
 
-static const int RWLOCK_WRITER   = 1;
-static const int RWLOCK_UPGRADED = 2;
-static const int RWLOCK_READER   = 4;
+static const int RWLOCK_WRITER   = 1<<0;
+static const int RWLOCK_UPGRADED = 1<<1;
+static const int RWLOCK_READER   = 1<<2;
 struct RWSpinLock {
 	Futex bits;
 };
@@ -467,7 +467,7 @@ bool rwlock_try_acquire_upgrade(RWSpinLock *l) {
 
 void rwlock_acquire_upgrade(RWSpinLock *l) {
 	while (!rwlock_try_acquire_upgrade(l)) {
-		futex_wait(&l->bits, RWLOCK_UPGRADED);
+		futex_wait(&l->bits, RWLOCK_UPGRADED | RWLOCK_WRITER);
 	}
 }
 void rwlock_release_upgrade(RWSpinLock *l) {
@@ -481,7 +481,7 @@ bool rwlock_try_release_upgrade_and_acquire_write(RWSpinLock *l) {
 
 void rwlock_release_upgrade_and_acquire_write(RWSpinLock *l) {
 	while (!rwlock_try_release_upgrade_and_acquire_write(l)) {
-		futex_wait(&l->bits, RWLOCK_WRITER);
+		futex_wait(&l->bits, RWLOCK_UPGRADED);
 	}
 }