authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-18 17:02:39-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-20 20:59:52-08:00
logce00e91aa51f05925a297c7d6dc16c37a41fc151
tree866c0e72bf95bd98de8e2d3b6553a5cf12172ebe
parent160445ef316f76dfddfa17b11c4919a3e14f486d

Compilation pipeline: do musl jobs earlier

This means doing more work in parallel which is already good, but it's also a correctnes fix because we need link_task_wait_group.wait() to ensure that no more linker inputs will be generated.

1 files changed, 59 insertions(+), 43 deletions(-)

src/Compilation.zig+59-43
...@@ -122,6 +122,10 @@ link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,...@@ -122,6 +122,10 @@ link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty,
122/// the linker task thread.122/// the linker task thread.
123remaining_prelink_tasks: u32,123remaining_prelink_tasks: u32,
124124
125/// Set of work that can be represented by only flags to determine whether the
126/// work is queued or not.
127queued_jobs: QueuedJobs,
128
125work_queues: [129work_queues: [
126 len: {130 len: {
127 var len: usize = 0;131 var len: usize = 0;
...@@ -193,10 +197,6 @@ stack_report: bool,...@@ -193,10 +197,6 @@ stack_report: bool,
193debug_compiler_runtime_libs: bool,197debug_compiler_runtime_libs: bool,
194debug_compile_errors: bool,198debug_compile_errors: bool,
195incremental: bool,199incremental: bool,
196job_queued_compiler_rt_lib: bool = false,
197job_queued_compiler_rt_obj: bool = false,
198job_queued_fuzzer_lib: bool = false,
199job_queued_update_builtin_zig: bool,
200alloc_failure_occurred: bool = false,200alloc_failure_occurred: bool = false,
201last_update_was_cache_hit: bool = false,201last_update_was_cache_hit: bool = false,
202202
...@@ -234,13 +234,13 @@ tsan_lib: ?CrtFile = null,...@@ -234,13 +234,13 @@ tsan_lib: ?CrtFile = null,
234/// and resolved before calling linker.flush().234/// and resolved before calling linker.flush().
235libc_static_lib: ?CrtFile = null,235libc_static_lib: ?CrtFile = null,
236/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated236/// Populated when we build the libcompiler_rt static library. A Job to build this is indicated
237/// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().237/// by setting `queued_jobs.compiler_rt_lib` and resolved before calling linker.flush().
238compiler_rt_lib: ?CrtFile = null,238compiler_rt_lib: ?CrtFile = null,
239/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated239/// Populated when we build the compiler_rt_obj object. A Job to build this is indicated
240/// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().240/// by setting `queued_jobs.compiler_rt_obj` and resolved before calling linker.flush().
241compiler_rt_obj: ?CrtFile = null,241compiler_rt_obj: ?CrtFile = null,
242/// Populated when we build the libfuzzer static library. A Job to build this242/// Populated when we build the libfuzzer static library. A Job to build this
243/// is indicated by setting `job_queued_fuzzer_lib` and resolved before243/// is indicated by setting `queued_jobs.fuzzer_lib` and resolved before
244/// calling linker.flush().244/// calling linker.flush().
245fuzzer_lib: ?CrtFile = null,245fuzzer_lib: ?CrtFile = null,
246246
...@@ -284,6 +284,14 @@ file_system_inputs: ?*std.ArrayListUnmanaged(u8),...@@ -284,6 +284,14 @@ file_system_inputs: ?*std.ArrayListUnmanaged(u8),
284/// This digest will be known after update() is called.284/// This digest will be known after update() is called.
285digest: ?[Cache.bin_digest_len]u8 = null,285digest: ?[Cache.bin_digest_len]u8 = null,
286286
287const QueuedJobs = struct {
288 compiler_rt_lib: bool = false,
289 compiler_rt_obj: bool = false,
290 fuzzer_lib: bool = false,
291 update_builtin_zig: bool,
292 musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = [1]bool{false} ** @typeInfo(musl.CrtFile).@"enum".fields.len,
293};
294
287pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;295pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
288pub const SemaError = Zcu.SemaError;296pub const SemaError = Zcu.SemaError;
289297
...@@ -381,8 +389,6 @@ const Job = union(enum) {...@@ -381,8 +389,6 @@ const Job = union(enum) {
381 glibc_crt_file: glibc.CrtFile,389 glibc_crt_file: glibc.CrtFile,
382 /// all of the glibc shared objects390 /// all of the glibc shared objects
383 glibc_shared_objects,391 glibc_shared_objects,
384 /// one of the musl static objects
385 musl_crt_file: musl.CrtFile,
386 /// one of the mingw-w64 static objects392 /// one of the mingw-w64 static objects
387 mingw_crt_file: mingw.CrtFile,393 mingw_crt_file: mingw.CrtFile,
388394
...@@ -1512,7 +1518,9 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1512,7 +1518,9 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1512 .framework_dirs = options.framework_dirs,1518 .framework_dirs = options.framework_dirs,
1513 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,1519 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
1514 .skip_linker_dependencies = options.skip_linker_dependencies,1520 .skip_linker_dependencies = options.skip_linker_dependencies,
1515 .job_queued_update_builtin_zig = have_zcu,1521 .queued_jobs = .{
1522 .update_builtin_zig = have_zcu,
1523 },
1516 .function_sections = options.function_sections,1524 .function_sections = options.function_sections,
1517 .data_sections = options.data_sections,1525 .data_sections = options.data_sections,
1518 .native_system_include_paths = options.native_system_include_paths,1526 .native_system_include_paths = options.native_system_include_paths,
...@@ -1805,20 +1813,18 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1805,20 +1813,18 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1805 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1813 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
18061814
1807 if (musl.needsCrtiCrtn(target)) {1815 if (musl.needsCrtiCrtn(target)) {
1808 try comp.queueJobs(&[_]Job{1816 comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.crti_o)] = true;
1809 .{ .musl_crt_file = .crti_o },1817 comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.crtn_o)] = true;
1810 .{ .musl_crt_file = .crtn_o },
1811 });
1812 comp.remaining_prelink_tasks += 2;1818 comp.remaining_prelink_tasks += 2;
1813 }1819 }
1814 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {1820 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| {
1815 try comp.queueJobs(&.{.{ .musl_crt_file = f }});1821 comp.queued_jobs.musl_crt_file[@intFromEnum(f)] = true;
1816 comp.remaining_prelink_tasks += 1;1822 comp.remaining_prelink_tasks += 1;
1817 }1823 }
1818 try comp.queueJobs(&.{.{ .musl_crt_file = switch (comp.config.link_mode) {1824 switch (comp.config.link_mode) {
1819 .static => .libc_a,1825 .static => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_a)] = true,
1820 .dynamic => .libc_so,1826 .dynamic => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_so)] = true,
1821 } }});1827 }
1822 comp.remaining_prelink_tasks += 1;1828 comp.remaining_prelink_tasks += 1;
1823 } else if (target.isGnuLibC()) {1829 } else if (target.isGnuLibC()) {
1824 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;1830 if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
...@@ -1916,20 +1922,20 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1916,20 +1922,20 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1916 if (comp.include_compiler_rt and capable_of_building_compiler_rt) {1922 if (comp.include_compiler_rt and capable_of_building_compiler_rt) {
1917 if (is_exe_or_dyn_lib) {1923 if (is_exe_or_dyn_lib) {
1918 log.debug("queuing a job to build compiler_rt_lib", .{});1924 log.debug("queuing a job to build compiler_rt_lib", .{});
1919 comp.job_queued_compiler_rt_lib = true;1925 comp.queued_jobs.compiler_rt_lib = true;
1920 comp.remaining_prelink_tasks += 1;1926 comp.remaining_prelink_tasks += 1;
1921 } else if (output_mode != .Obj) {1927 } else if (output_mode != .Obj) {
1922 log.debug("queuing a job to build compiler_rt_obj", .{});1928 log.debug("queuing a job to build compiler_rt_obj", .{});
1923 // In this case we are making a static library, so we ask1929 // In this case we are making a static library, so we ask
1924 // for a compiler-rt object to put in it.1930 // for a compiler-rt object to put in it.
1925 comp.job_queued_compiler_rt_obj = true;1931 comp.queued_jobs.compiler_rt_obj = true;
1926 comp.remaining_prelink_tasks += 1;1932 comp.remaining_prelink_tasks += 1;
1927 }1933 }
1928 }1934 }
19291935
1930 if (is_exe_or_dyn_lib and comp.config.any_fuzz and capable_of_building_compiler_rt) {1936 if (is_exe_or_dyn_lib and comp.config.any_fuzz and capable_of_building_compiler_rt) {
1931 log.debug("queuing a job to build libfuzzer", .{});1937 log.debug("queuing a job to build libfuzzer", .{});
1932 comp.job_queued_fuzzer_lib = true;1938 comp.queued_jobs.fuzzer_lib = true;
1933 comp.remaining_prelink_tasks += 1;1939 comp.remaining_prelink_tasks += 1;
1934 }1940 }
1935 }1941 }
...@@ -3712,21 +3718,24 @@ fn performAllTheWorkInner(...@@ -3712,21 +3718,24 @@ fn performAllTheWorkInner(
3712 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });3718 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
3713 }3719 }
37143720
3715 if (comp.job_queued_compiler_rt_lib) {3721 if (testAndClear(&comp.queued_jobs.compiler_rt_lib)) {
3716 comp.job_queued_compiler_rt_lib = false;
3717 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node });3722 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node });
3718 }3723 }
37193724
3720 if (comp.job_queued_compiler_rt_obj) {3725 if (testAndClear(&comp.queued_jobs.compiler_rt_obj)) {
3721 comp.job_queued_compiler_rt_obj = false;
3722 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node });3726 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node });
3723 }3727 }
37243728
3725 if (comp.job_queued_fuzzer_lib) {3729 if (testAndClear(&comp.queued_jobs.fuzzer_lib)) {
3726 comp.job_queued_fuzzer_lib = false;
3727 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node });3730 comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node });
3728 }3731 }
37293732
3733 inline for (@typeInfo(musl.CrtFile).@"enum".fields) |field| {
3734 const tag = @field(musl.CrtFile, field.name);
3735 if (testAndClear(&comp.queued_jobs.musl_crt_file[@intFromEnum(tag)]))
3736 comp.link_task_wait_group.spawnManager(buildMuslCrtFile, .{ comp, tag, main_progress_node });
3737 }
3738
3730 {3739 {
3731 const astgen_frame = tracy.namedFrame("astgen");3740 const astgen_frame = tracy.namedFrame("astgen");
3732 defer astgen_frame.end();3741 defer astgen_frame.end();
...@@ -3741,8 +3750,8 @@ fn performAllTheWorkInner(...@@ -3741,8 +3750,8 @@ fn performAllTheWorkInner(
3741 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files3750 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files
3742 // 2. optimization; in the hot path it only incurs a stat() syscall, which happens3751 // 2. optimization; in the hot path it only incurs a stat() syscall, which happens
3743 // in the `astgen_wait_group`.3752 // in the `astgen_wait_group`.
3744 if (comp.job_queued_update_builtin_zig) b: {3753 if (comp.queued_jobs.update_builtin_zig) b: {
3745 comp.job_queued_update_builtin_zig = false;3754 comp.queued_jobs.update_builtin_zig = false;
3746 if (comp.zcu == null) break :b;3755 if (comp.zcu == null) break :b;
3747 // TODO put all the modules in a flat array to make them easy to iterate.3756 // TODO put all the modules in a flat array to make them easy to iterate.
3748 var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .empty;3757 var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .empty;
...@@ -3821,6 +3830,7 @@ fn performAllTheWorkInner(...@@ -3821,6 +3830,7 @@ fn performAllTheWorkInner(
3821 comp.link_task_wait_group.wait();3830 comp.link_task_wait_group.wait();
3822 comp.link_task_wait_group.reset();3831 comp.link_task_wait_group.reset();
3823 std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{});3832 std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{});
3833 assert(comp.remaining_prelink_tasks == 0);
3824 }3834 }
38253835
3826 work: while (true) {3836 work: while (true) {
...@@ -3980,19 +3990,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3980,19 +3990,6 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3980 );3990 );
3981 };3991 };
3982 },3992 },
3983 .musl_crt_file => |crt_file| {
3984 const named_frame = tracy.namedFrame("musl_crt_file");
3985 defer named_frame.end();
3986
3987 musl.buildCrtFile(comp, crt_file, prog_node) catch |err| {
3988 // TODO Surface more error details.
3989 comp.lockAndSetMiscFailure(
3990 .musl_crt_file,
3991 "unable to build musl CRT file: {s}",
3992 .{@errorName(err)},
3993 );
3994 };
3995 },
3996 .mingw_crt_file => |crt_file| {3993 .mingw_crt_file => |crt_file| {
3997 const named_frame = tracy.namedFrame("mingw_crt_file");3994 const named_frame = tracy.namedFrame("mingw_crt_file");
3998 defer named_frame.end();3995 defer named_frame.end();
...@@ -4761,6 +4758,19 @@ fn buildRt(...@@ -4761,6 +4758,19 @@ fn buildRt(
4761 };4758 };
4762}4759}
47634760
4761fn buildMuslCrtFile(
4762 comp: *Compilation,
4763 crt_file: musl.CrtFile,
4764 prog_node: std.Progress.Node,
4765) void {
4766 musl.buildCrtFile(comp, crt_file, prog_node) catch |err| switch (err) {
4767 error.SubCompilationFailed => return, // error reported already
4768 else => comp.lockAndSetMiscFailure(.musl_crt_file, "unable to build musl {s}: {s}", .{
4769 @tagName(crt_file), @errorName(err),
4770 }),
4771 };
4772}
4773
4764fn reportRetryableCObjectError(4774fn reportRetryableCObjectError(
4765 comp: *Compilation,4775 comp: *Compilation,
4766 c_object: *CObject,4776 c_object: *CObject,
...@@ -6805,3 +6815,9 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {...@@ -6805,3 +6815,9 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {
6805pub fn compilerRtStrip(comp: Compilation) bool {6815pub fn compilerRtStrip(comp: Compilation) bool {
6806 return comp.root_mod.strip;6816 return comp.root_mod.strip;
6807}6817}
6818
6819fn testAndClear(b: *bool) bool {
6820 const result = b.*;
6821 b.* = false;
6822 return result;
6823}