impl shared thread pool mode

This commit is contained in:
Nikita Smith
2025-01-20 21:41:24 -08:00
parent e1e7fb745e
commit d3fbc858b8
5 changed files with 118 additions and 68 deletions
+6 -1
View File
@@ -3189,7 +3189,12 @@ lnk_run(int argc, char **argv)
LNK_Config *config = lnk_build_config(scratch.arena, argc, argv); LNK_Config *config = lnk_build_config(scratch.arena, argc, argv);
TP_Context *tp = tp_alloc(scratch.arena, config->worker_count); TP_Context *tp;
if (config->shared_thread_pool == LNK_SwitchState_Yes) {
tp = tp_alloc_shared(scratch.arena, config->worker_count, config->shared_thread_pool_mutex_name);
} else {
tp = tp_alloc(scratch.arena, config->worker_count);
}
TP_Arena *tp_arena = tp_arena_alloc(tp); TP_Arena *tp_arena = tp_arena_alloc(tp);
#if PROFILE_TELEMETRY #if PROFILE_TELEMETRY
+13
View File
@@ -150,6 +150,8 @@ global read_only struct
{ LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." }, { LNK_CmdSwitch_Rad_PdbHashTypeNameMap, "RAD_PDB_HASH_TYPE_NAME_MAP", ":FILENAME", "Produce map file with hash -> type name mappings." },
{ LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." }, { LNK_CmdSwitch_Rad_PdbHashTypeNames, "RAD_PDB_HASH_TYPE_NAMES", ":{NONE|LENIENT|FULL}", "Replace type names in LF_STRUCTURE and LF_CLASS with hashes." },
{ LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." }, { LNK_CmdSwitch_Rad_SectVirtOff, "RAD_SECT_VIRT_OFF", ":#", "Set RVA where section data is placed in memory. For internal use only." },
{ LNK_CmdSwitch_Rad_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:NO]", "" },
{ LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RAD_SHARED_THREAD_POOL_MUTEX_NAME", ":STRING", "" },
{ LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" }, { LNK_CmdSwitch_Rad_SuppressError, "RAD_SUPPRESS_ERROR", ":#", "" },
{ LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." }, { LNK_CmdSwitch_Rad_SymbolTableCapDefined, "RAD_SYMBOL_TABLE_CAP_DEFINED", ":#", "Number of buckets allocated in the symbol table for defined symbols." },
{ LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." }, { LNK_CmdSwitch_Rad_SymbolTableCapInternal, "RAD_SYMBOL_TABLE_CAP_INTERNAL", ":#", "Number of buckets allocated in the symbol table for internal symbols." },
@@ -944,6 +946,8 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string)
internal void internal void
lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path) lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path)
{ {
Assert(cmd_name.size); // switch must have a defined name in the table
Temp scratch = scratch_begin(&arena,1); Temp scratch = scratch_begin(&arena,1);
LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name);
@@ -1672,6 +1676,14 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam
} }
} break; } break;
case LNK_CmdSwitch_Rad_SharedThreadPool: {
lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool);
} break;
case LNK_CmdSwitch_Rad_SharedThreadPoolMutexName: {
lnk_cmd_switch_parse_string(obj_path, lib_path, cmd_switch, value_strings, &config->shared_thread_pool_mutex_name);
} break;
case LNK_CmdSwitch_Rad_SuppressError: { case LNK_CmdSwitch_Rad_SuppressError: {
U64List error_code_list = {0}; U64List error_code_list = {0};
if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) { if (lnk_cmd_switch_parse_u64_list(scratch.arena, obj_path, lib_path, cmd_switch, value_strings, &error_code_list, 0)) {
@@ -1782,6 +1794,7 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line)
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapWeak, "0x3ffff");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SymbolTableCapLib, "0x3ffff");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%"); lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_DebugAltPath, "%%_RAD_RDI_PATH%%");
lnk_cmd_line_push_option_if_not_presentf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_SharedThreadPoolMutexName, "RADLINK_THREAD_POOL_MUTEX");
#if BUILD_DEBUG #if BUILD_DEBUG
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "debug");
lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write"); lnk_cmd_line_push_optionf(scratch.arena, &cmd_line, LNK_CmdSwitch_Rad_Log, "io_write");
+4
View File
@@ -147,6 +147,8 @@ typedef enum
LNK_CmdSwitch_Rad_PdbHashTypeNameMap, LNK_CmdSwitch_Rad_PdbHashTypeNameMap,
LNK_CmdSwitch_Rad_PdbHashTypeNameLength, LNK_CmdSwitch_Rad_PdbHashTypeNameLength,
LNK_CmdSwitch_Rad_SectVirtOff, LNK_CmdSwitch_Rad_SectVirtOff,
LNK_CmdSwitch_Rad_SharedThreadPool,
LNK_CmdSwitch_Rad_SharedThreadPoolMutexName,
LNK_CmdSwitch_Rad_SuppressError, LNK_CmdSwitch_Rad_SuppressError,
LNK_CmdSwitch_Rad_SymbolTableCapDefined, LNK_CmdSwitch_Rad_SymbolTableCapDefined,
LNK_CmdSwitch_Rad_SymbolTableCapInternal, LNK_CmdSwitch_Rad_SymbolTableCapInternal,
@@ -310,6 +312,8 @@ typedef struct LNK_Config
U64 pdb_page_size; U64 pdb_page_size;
U64 worker_count; U64 worker_count;
U64 idle_worker_count; U64 idle_worker_count;
LNK_SwitchState shared_thread_pool;
String8 shared_thread_pool_mutex_name;
U64 *function_pad_min; U64 *function_pad_min;
U64 *manifest_resource_id; U64 *manifest_resource_id;
B32 no_default_libs; B32 no_default_libs;
+25
View File
@@ -81,12 +81,25 @@ tp_alloc(Arena *arena, U32 worker_count)
return pool; return pool;
} }
internal TP_Context *
tp_alloc_shared(Arena *arena, U32 worker_count, String8 name)
{
TP_Context *tp = tp_alloc(arena, worker_count);
tp->shared_mutex_name = name;
tp->shared_mutex_handle = os_shared_mutex_alloc(name);
AssertAlways(!os_handle_match(tp->shared_mutex_handle, os_handle_zero()));
return tp;
}
internal void internal void
tp_release(TP_Context *pool) tp_release(TP_Context *pool)
{ {
pool->is_live = 0; pool->is_live = 0;
os_semaphore_release(pool->task_semaphore); os_semaphore_release(pool->task_semaphore);
os_semaphore_release(pool->main_semaphore); os_semaphore_release(pool->main_semaphore);
if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) {
os_mutex_release(pool->shared_mutex_handle);
}
for (U64 i = 1; i < pool->worker_count; i += 1) { for (U64 i = 1; i < pool->worker_count; i += 1) {
os_thread_detach(pool->worker_arr[i].handle); os_thread_detach(pool->worker_arr[i].handle);
} }
@@ -160,6 +173,13 @@ tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *
{ {
Assert(!arena || arena->count == pool->worker_count); Assert(!arena || arena->count == pool->worker_count);
// in shared mode take mutex
if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) {
if (!os_shared_mutex_take(pool->shared_mutex_handle, max_U64)) {
AssertAlways(!"failed to take shared mutex");
}
}
// setup pool state // setup pool state
pool->worker_arena = arena; pool->worker_arena = arena;
pool->task_count = task_count; pool->task_count = task_count;
@@ -183,6 +203,11 @@ tp_for_parallel(TP_Context *pool, TP_Arena *arena, U64 task_count, TP_TaskFunc *
// wait for workers to finish assigned tasks // wait for workers to finish assigned tasks
os_semaphore_take(pool->main_semaphore, max_U64); os_semaphore_take(pool->main_semaphore, max_U64);
} }
// signal other thread pools that we have done our round of tasks
if (!os_handle_match(pool->shared_mutex_handle, os_handle_zero())) {
os_shared_mutex_drop(pool->shared_mutex_handle);
}
} }
internal Rng1U64 * internal Rng1U64 *
+3
View File
@@ -29,6 +29,8 @@ typedef struct TP_Context
{ {
OS_Handle task_semaphore; OS_Handle task_semaphore;
OS_Handle main_semaphore; OS_Handle main_semaphore;
OS_Handle shared_mutex_handle;
String8 shared_mutex_name;
B32 is_live; B32 is_live;
U32 worker_count; U32 worker_count;
TP_Worker *worker_arr; TP_Worker *worker_arr;
@@ -41,6 +43,7 @@ typedef struct TP_Context
} TP_Context; } TP_Context;
internal TP_Context * tp_alloc(Arena *arena, U32 worker_count); internal TP_Context * tp_alloc(Arena *arena, U32 worker_count);
internal TP_Context * tp_alloc_shared(Arena *arena, U32 worker_count, String8 name);
internal void tp_release(TP_Context *pool); internal void tp_release(TP_Context *pool);
internal TP_Arena * tp_arena_alloc(TP_Context *pool); internal TP_Arena * tp_arena_alloc(TP_Context *pool);
internal void tp_arena_release(TP_Arena **arena_ptr); internal void tp_arena_release(TP_Arena **arena_ptr);