authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-25 07:12:39-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-25 07:12:39-07:00
logb22357b88b44e47a9c0347cb47d2be2ed3c461a1
tree06f0b86b53d99bce9a11a5f76eee90d3daaa6899
parent18685e928dcf179271a18cec3d8d16ed0547d3b5
parent94f4f9c4ef31570589e5572c86947eb4a2fd58ac
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20783 from ziglang/cache-fix

build compiler_rt and fuzzer in parallel; fix false positive cache hits

3 files changed, 90 insertions(+), 27 deletions(-)

lib/std/Build/Cache.zig+31
...@@ -1024,6 +1024,37 @@ pub const Manifest = struct {...@@ -1024,6 +1024,37 @@ pub const Manifest = struct {
1024 buf.items.len -= 1;1024 buf.items.len -= 1;
1025 }1025 }
1026 }1026 }
1027
1028 pub fn populateOtherManifest(man: *Manifest, other: *Manifest, prefix_map: [4]u8) Allocator.Error!void {
1029 const gpa = other.cache.gpa;
1030 assert(@typeInfo(std.zig.Server.Message.PathPrefix).Enum.fields.len == man.cache.prefixes_len);
1031 assert(man.cache.prefixes_len == 4);
1032 for (man.files.keys()) |file| {
1033 const prefixed_path: PrefixedPath = .{
1034 .prefix = prefix_map[file.prefixed_path.prefix],
1035 .sub_path = try gpa.dupe(u8, file.prefixed_path.sub_path),
1036 };
1037 errdefer gpa.free(prefixed_path.sub_path);
1038
1039 const gop = try other.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});
1040 errdefer _ = other.files.pop();
1041
1042 if (gop.found_existing) {
1043 gpa.free(prefixed_path.sub_path);
1044 continue;
1045 }
1046
1047 gop.key_ptr.* = .{
1048 .prefixed_path = prefixed_path,
1049 .max_file_size = file.max_file_size,
1050 .stat = file.stat,
1051 .bin_digest = file.bin_digest,
1052 .contents = null,
1053 };
1054
1055 other.hash.hasher.update(&gop.key_ptr.bin_digest);
1056 }
1057 }
1027};1058};
10281059
1029/// On operating systems that support symlinks, does a readlink. On other operating systems,1060/// On operating systems that support symlinks, does a readlink. On other operating systems,
src/Compilation.zig+56-26
...@@ -201,6 +201,9 @@ c_source_files: []const CSourceFile,...@@ -201,6 +201,9 @@ c_source_files: []const CSourceFile,
201rc_source_files: []const RcSourceFile,201rc_source_files: []const RcSourceFile,
202global_cc_argv: []const []const u8,202global_cc_argv: []const []const u8,
203cache_parent: *Cache,203cache_parent: *Cache,
204/// Populated when a sub-Compilation is created during the `update` of its parent.
205/// In this case the child must additionally add file system inputs to this object.
206parent_whole_cache: ?ParentWholeCache,
204/// Path to own executable for invoking `zig clang`.207/// Path to own executable for invoking `zig clang`.
205self_exe_path: ?[]const u8,208self_exe_path: ?[]const u8,
206zig_lib_directory: Directory,209zig_lib_directory: Directory,
...@@ -262,9 +265,6 @@ emit_asm: ?EmitLoc,...@@ -262,9 +265,6 @@ emit_asm: ?EmitLoc,
262emit_llvm_ir: ?EmitLoc,265emit_llvm_ir: ?EmitLoc,
263emit_llvm_bc: ?EmitLoc,266emit_llvm_bc: ?EmitLoc,
264267
265work_queue_wait_group: WaitGroup = .{},
266astgen_wait_group: WaitGroup = .{},
267
268llvm_opt_bisect_limit: c_int,268llvm_opt_bisect_limit: c_int,
269269
270file_system_inputs: ?*std.ArrayListUnmanaged(u8),270file_system_inputs: ?*std.ArrayListUnmanaged(u8),
...@@ -973,6 +973,12 @@ pub const SystemLib = link.SystemLib;...@@ -973,6 +973,12 @@ pub const SystemLib = link.SystemLib;
973973
974pub const CacheMode = enum { incremental, whole };974pub const CacheMode = enum { incremental, whole };
975975
976pub const ParentWholeCache = struct {
977 manifest: *Cache.Manifest,
978 mutex: *std.Thread.Mutex,
979 prefix_map: [4]u8,
980};
981
976const CacheUse = union(CacheMode) {982const CacheUse = union(CacheMode) {
977 incremental: *Incremental,983 incremental: *Incremental,
978 whole: *Whole,984 whole: *Whole,
...@@ -1210,6 +1216,8 @@ pub const CreateOptions = struct {...@@ -1210,6 +1216,8 @@ pub const CreateOptions = struct {
1210 /// Tracks all files that can cause the Compilation to be invalidated and need a rebuild.1216 /// Tracks all files that can cause the Compilation to be invalidated and need a rebuild.
1211 file_system_inputs: ?*std.ArrayListUnmanaged(u8) = null,1217 file_system_inputs: ?*std.ArrayListUnmanaged(u8) = null,
12121218
1219 parent_whole_cache: ?ParentWholeCache = null,
1220
1213 pub const Entry = link.File.OpenOptions.Entry;1221 pub const Entry = link.File.OpenOptions.Entry;
1214};1222};
12151223
...@@ -1566,6 +1574,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1566,6 +1574,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1566 .link_eh_frame_hdr = link_eh_frame_hdr,1574 .link_eh_frame_hdr = link_eh_frame_hdr,
1567 .global_cc_argv = options.global_cc_argv,1575 .global_cc_argv = options.global_cc_argv,
1568 .file_system_inputs = options.file_system_inputs,1576 .file_system_inputs = options.file_system_inputs,
1577 .parent_whole_cache = options.parent_whole_cache,
1569 };1578 };
15701579
1571 // Prevent some footguns by making the "any" fields of config reflect1580 // Prevent some footguns by making the "any" fields of config reflect
...@@ -2109,6 +2118,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2109,6 +2118,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2109 if (is_hit) {2118 if (is_hit) {
2110 // In this case the cache hit contains the full set of file system inputs. Nice!2119 // In this case the cache hit contains the full set of file system inputs. Nice!
2111 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);2120 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
2121 if (comp.parent_whole_cache) |pwc| {
2122 pwc.mutex.lock();
2123 defer pwc.mutex.unlock();
2124 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
2125 }
21122126
2113 comp.last_update_was_cache_hit = true;2127 comp.last_update_was_cache_hit = true;
2114 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});2128 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
...@@ -2306,6 +2320,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2306,6 +2320,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2306 switch (comp.cache_use) {2320 switch (comp.cache_use) {
2307 .whole => |whole| {2321 .whole => |whole| {
2308 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);2322 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
2323 if (comp.parent_whole_cache) |pwc| {
2324 pwc.mutex.lock();
2325 defer pwc.mutex.unlock();
2326 try man.populateOtherManifest(pwc.manifest, pwc.prefix_map);
2327 }
23092328
2310 const digest = man.final();2329 const digest = man.final();
23112330
...@@ -3535,13 +3554,13 @@ fn performAllTheWorkInner(...@@ -3535,13 +3554,13 @@ fn performAllTheWorkInner(
3535 // (at least for now) single-threaded main work queue. However, C object compilation3554 // (at least for now) single-threaded main work queue. However, C object compilation
3536 // only needs to be finished by the end of this function.3555 // only needs to be finished by the end of this function.
35373556
3538 comp.work_queue_wait_group.reset();3557 var work_queue_wait_group: WaitGroup = .{};
3539 defer comp.work_queue_wait_group.wait();3558 defer work_queue_wait_group.wait();
35403559
3541 if (comp.docs_emit != null) {3560 if (comp.docs_emit != null) {
3542 dev.check(.docs_emit);3561 dev.check(.docs_emit);
3543 comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp});3562 comp.thread_pool.spawnWg(&work_queue_wait_group, workerDocsCopy, .{comp});
3544 comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });3563 work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
3545 }3564 }
35463565
3547 {3566 {
...@@ -3551,8 +3570,8 @@ fn performAllTheWorkInner(...@@ -3551,8 +3570,8 @@ fn performAllTheWorkInner(
3551 const zir_prog_node = main_progress_node.start("AST Lowering", 0);3570 const zir_prog_node = main_progress_node.start("AST Lowering", 0);
3552 defer zir_prog_node.end();3571 defer zir_prog_node.end();
35533572
3554 comp.astgen_wait_group.reset();3573 var astgen_wait_group: WaitGroup = .{};
3555 defer comp.astgen_wait_group.wait();3574 defer astgen_wait_group.wait();
35563575
3557 // builtin.zig is handled specially for two reasons:3576 // builtin.zig is handled specially for two reasons:
3558 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files3577 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files
...@@ -3574,7 +3593,7 @@ fn performAllTheWorkInner(...@@ -3574,7 +3593,7 @@ fn performAllTheWorkInner(
35743593
3575 const file = mod.builtin_file orelse continue;3594 const file = mod.builtin_file orelse continue;
35763595
3577 comp.thread_pool.spawnWg(&comp.astgen_wait_group, workerUpdateBuiltinZigFile, .{3596 comp.thread_pool.spawnWg(&astgen_wait_group, workerUpdateBuiltinZigFile, .{
3578 comp, mod, file,3597 comp, mod, file,
3579 });3598 });
3580 }3599 }
...@@ -3594,32 +3613,36 @@ fn performAllTheWorkInner(...@@ -3594,32 +3613,36 @@ fn performAllTheWorkInner(
3594 const path_digest = zcu.filePathDigest(file_index);3613 const path_digest = zcu.filePathDigest(file_index);
3595 const root_decl = zcu.fileRootDecl(file_index);3614 const root_decl = zcu.fileRootDecl(file_index);
3596 const file = zcu.fileByIndex(file_index);3615 const file = zcu.fileByIndex(file_index);
3597 comp.thread_pool.spawnWgId(&comp.astgen_wait_group, workerAstGenFile, .{3616 comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{
3598 comp, file, file_index, path_digest, root_decl, zir_prog_node, &comp.astgen_wait_group, .root,3617 comp, file, file_index, path_digest, root_decl, zir_prog_node, &astgen_wait_group, .root,
3599 });3618 });
3600 }3619 }
3601 }3620 }
36023621
3603 while (comp.embed_file_work_queue.readItem()) |embed_file| {3622 while (comp.embed_file_work_queue.readItem()) |embed_file| {
3604 comp.thread_pool.spawnWg(&comp.astgen_wait_group, workerCheckEmbedFile, .{3623 comp.thread_pool.spawnWg(&astgen_wait_group, workerCheckEmbedFile, .{
3605 comp, embed_file,3624 comp, embed_file,
3606 });3625 });
3607 }3626 }
3608 }3627 }
36093628
3610 while (comp.c_object_work_queue.readItem()) |c_object| {3629 while (comp.c_object_work_queue.readItem()) |c_object| {
3611 comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateCObject, .{3630 comp.thread_pool.spawnWg(&work_queue_wait_group, workerUpdateCObject, .{
3612 comp, c_object, main_progress_node,3631 comp, c_object, main_progress_node,
3613 });3632 });
3614 }3633 }
36153634
3616 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {3635 while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
3617 comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{3636 comp.thread_pool.spawnWg(&work_queue_wait_group, workerUpdateWin32Resource, .{
3618 comp, win32_resource, main_progress_node,3637 comp, win32_resource, main_progress_node,
3619 });3638 });
3620 }3639 }
3621 }3640 }
36223641
3642 if (comp.job_queued_compiler_rt_lib) work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node });
3643 if (comp.job_queued_compiler_rt_obj) work_queue_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node });
3644 if (comp.job_queued_fuzzer_lib) work_queue_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node });
3645
3623 if (comp.module) |zcu| {3646 if (comp.module) |zcu| {
3624 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };3647 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
3625 if (comp.incremental) {3648 if (comp.incremental) {
...@@ -3633,7 +3656,7 @@ fn performAllTheWorkInner(...@@ -3633,7 +3656,7 @@ fn performAllTheWorkInner(
3633 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);3656 zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
3634 }3657 }
36353658
3636 if (!InternPool.single_threaded) comp.thread_pool.spawnWgId(&comp.work_queue_wait_group, codegenThread, .{comp});3659 if (!InternPool.single_threaded) comp.thread_pool.spawnWgId(&work_queue_wait_group, codegenThread, .{comp});
3637 defer if (!InternPool.single_threaded) {3660 defer if (!InternPool.single_threaded) {
3638 {3661 {
3639 comp.codegen_work.mutex.lock();3662 comp.codegen_work.mutex.lock();
...@@ -3661,10 +3684,6 @@ fn performAllTheWorkInner(...@@ -3661,10 +3684,6 @@ fn performAllTheWorkInner(
3661 }3684 }
3662 break;3685 break;
3663 }3686 }
3664
3665 buildCompilerRtOneShot(comp, &comp.job_queued_compiler_rt_lib, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node);
3666 buildCompilerRtOneShot(comp, &comp.job_queued_compiler_rt_obj, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node);
3667 buildCompilerRtOneShot(comp, &comp.job_queued_fuzzer_lib, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node);
3668}3687}
36693688
3670const JobError = Allocator.Error;3689const JobError = Allocator.Error;
...@@ -4668,18 +4687,14 @@ fn workerUpdateWin32Resource(...@@ -4668,18 +4687,14 @@ fn workerUpdateWin32Resource(
4668 };4687 };
4669}4688}
46704689
4671fn buildCompilerRtOneShot(4690fn buildRt(
4672 comp: *Compilation,4691 comp: *Compilation,
4673 job_queued: *bool,
4674 root_source_name: []const u8,4692 root_source_name: []const u8,
4675 misc_task: MiscTask,4693 misc_task: MiscTask,
4676 output_mode: std.builtin.OutputMode,4694 output_mode: std.builtin.OutputMode,
4677 out: *?CRTFile,4695 out: *?CRTFile,
4678 prog_node: std.Progress.Node,4696 prog_node: std.Progress.Node,
4679) void {4697) void {
4680 if (!job_queued.*) return;
4681 job_queued.* = false;
4682
4683 comp.buildOutputFromZig(4698 comp.buildOutputFromZig(
4684 root_source_name,4699 root_source_name,
4685 output_mode,4700 output_mode,
...@@ -6427,14 +6442,29 @@ fn buildOutputFromZig(...@@ -6427,14 +6442,29 @@ fn buildOutputFromZig(
6427 .output_mode = output_mode,6442 .output_mode = output_mode,
6428 });6443 });
64296444
6445 const parent_whole_cache: ?ParentWholeCache = switch (comp.cache_use) {
6446 .whole => |whole| .{
6447 .manifest = whole.cache_manifest.?,
6448 .mutex = &whole.cache_manifest_mutex,
6449 .prefix_map = .{
6450 0, // cwd is the same
6451 1, // zig lib dir is the same
6452 3, // local cache is mapped to global cache
6453 3, // global cache is the same
6454 },
6455 },
6456 .incremental => null,
6457 };
6458
6430 const sub_compilation = try Compilation.create(gpa, arena, .{6459 const sub_compilation = try Compilation.create(gpa, arena, .{
6431 .global_cache_directory = comp.global_cache_directory,6460 .global_cache_directory = comp.global_cache_directory,
6432 .local_cache_directory = comp.global_cache_directory,6461 .local_cache_directory = comp.global_cache_directory,
6433 .zig_lib_directory = comp.zig_lib_directory,6462 .zig_lib_directory = comp.zig_lib_directory,
6463 .cache_mode = .whole,
6464 .parent_whole_cache = parent_whole_cache,
6434 .self_exe_path = comp.self_exe_path,6465 .self_exe_path = comp.self_exe_path,
6435 .config = config,6466 .config = config,
6436 .root_mod = root_mod,6467 .root_mod = root_mod,
6437 .cache_mode = .whole,
6438 .root_name = root_name,6468 .root_name = root_name,
6439 .thread_pool = comp.thread_pool,6469 .thread_pool = comp.thread_pool,
6440 .libc_installation = comp.libc_installation,6470 .libc_installation = comp.libc_installation,
src/main.zig+3-1
...@@ -5309,7 +5309,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -5309,7 +5309,9 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
5309 const term = t: {5309 const term = t: {
5310 std.debug.lockStdErr();5310 std.debug.lockStdErr();
5311 defer std.debug.unlockStdErr();5311 defer std.debug.unlockStdErr();
5312 break :t try child.spawnAndWait();5312 break :t child.spawnAndWait() catch |err| {
5313 fatal("unable to spawn {s}: {s}", .{ child_argv.items[0], @errorName(err) });
5314 };
5313 };5315 };
53145316
5315 switch (term) {5317 switch (term) {