authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-22 15:09:46-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-22 15:09:46-07:00
log0710314de6b6ab30d43a9426e58379d4827b532e
tree41ba0e78d9c25c97fa5ff8d46a871dd0cc1fe0f4
parente011c31ee8e49bda4052ac9b74d088667dc310ba
parent5ae84696536ac184e6882f5c698b4a35e0e40d44
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15490 from kcbanner/skip_oom_steps

build_runner: add --skip-oom-steps

2 files changed, 34 insertions(+), 13 deletions(-)

lib/build_runner.zig+31-13
......@@ -93,6 +93,7 @@ pub fn main() !void {
9393 var dir_list = std.Build.DirList{};
9494 var summary: ?Summary = null;
9595 var max_rss: usize = 0;
96 var skip_oom_steps: bool = false;
9697 var color: Color = .auto;
9798
9899 const stderr_stream = io.getStdErr().writer();
......@@ -158,6 +159,8 @@ pub fn main() !void {
158159 });
159160 process.exit(1);
160161 };
162 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
163 skip_oom_steps = true;
161164 } else if (mem.eql(u8, arg, "--search-prefix")) {
162165 const search_prefix = nextArg(args, &arg_idx) orelse {
163166 std.debug.print("Expected argument after {s}\n\n", .{arg});
......@@ -305,6 +308,7 @@ pub fn main() !void {
305308 .max_rss = max_rss,
306309 .max_rss_is_default = false,
307310 .max_rss_mutex = .{},
311 .skip_oom_steps = skip_oom_steps,
308312 .memory_blocked_steps = std.ArrayList(*Step).init(arena),
309313
310314 .claimed_rss = 0,
......@@ -335,6 +339,7 @@ const Run = struct {
335339 max_rss: usize,
336340 max_rss_is_default: bool,
337341 max_rss_mutex: std.Thread.Mutex,
342 skip_oom_steps: bool,
338343 memory_blocked_steps: std.ArrayList(*Step),
339344
340345 claimed_rss: usize,
......@@ -383,10 +388,14 @@ fn runStepNames(
383388 for (step_stack.keys()) |s| {
384389 if (s.max_rss == 0) continue;
385390 if (s.max_rss > run.max_rss) {
386 std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
387 s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
388 });
389 any_problems = true;
391 if (run.skip_oom_steps) {
392 s.state = .skipped_oom;
393 } else {
394 std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
395 s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
396 });
397 any_problems = true;
398 }
390399 }
391400 }
392401 if (any_problems) {
......@@ -416,6 +425,7 @@ fn runStepNames(
416425 const steps_slice = step_stack.keys();
417426 for (0..steps_slice.len) |i| {
418427 const step = steps_slice[steps_slice.len - i - 1];
428 if (step.state == .skipped_oom) continue;
419429
420430 wait_group.start();
421431 thread_pool.spawn(workerMakeOneStep, .{
......@@ -461,7 +471,7 @@ fn runStepNames(
461471 },
462472 .dependency_failure => pending_count += 1,
463473 .success => success_count += 1,
464 .skipped => skipped_count += 1,
474 .skipped, .skipped_oom => skipped_count += 1,
465475 .failure => {
466476 failure_count += 1;
467477 const compile_errors_len = s.result_error_bundle.errorMessageCount();
......@@ -506,7 +516,7 @@ fn runStepNames(
506516 var print_node: PrintNode = .{ .parent = null };
507517 if (step_names.len == 0) {
508518 print_node.last = true;
509 printTreeStep(b, b.default_step, stderr, ttyconf, &print_node, &step_stack, failures_only) catch {};
519 printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack, failures_only) catch {};
510520 } else {
511521 const last_index = if (!failures_only) b.top_level_steps.count() else blk: {
512522 var i: usize = step_names.len;
......@@ -519,7 +529,7 @@ fn runStepNames(
519529 for (step_names, 0..) |step_name, i| {
520530 const tls = b.top_level_steps.get(step_name).?;
521531 print_node.last = i + 1 == last_index;
522 printTreeStep(b, &tls.step, stderr, ttyconf, &print_node, &step_stack, failures_only) catch {};
532 printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack, failures_only) catch {};
523533 }
524534 }
525535 }
......@@ -567,6 +577,7 @@ fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.io.tty.Config
567577fn printTreeStep(
568578 b: *std.Build,
569579 s: *Step,
580 run: *const Run,
570581 stderr: std.fs.File,
571582 ttyconf: std.io.tty.Config,
572583 parent_node: *PrintNode,
......@@ -654,13 +665,18 @@ fn printTreeStep(
654665 }
655666 try stderr.writeAll("\n");
656667 },
657
658 .skipped => {
668 .skipped, .skipped_oom => |skip| {
659669 try ttyconf.setColor(stderr, .yellow);
660 try stderr.writeAll(" skipped\n");
670 try stderr.writeAll(" skipped");
671 if (skip == .skipped_oom) {
672 try stderr.writeAll(" (not enough memory)");
673 try ttyconf.setColor(stderr, .dim);
674 try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
675 try ttyconf.setColor(stderr, .yellow);
676 }
677 try stderr.writeAll("\n");
661678 try ttyconf.setColor(stderr, .reset);
662679 },
663
664680 .failure => {
665681 if (s.result_error_bundle.errorMessageCount() > 0) {
666682 try ttyconf.setColor(stderr, .red);
......@@ -718,7 +734,7 @@ fn printTreeStep(
718734 .parent = parent_node,
719735 .last = i == last_index,
720736 };
721 try printTreeStep(b, dep, stderr, ttyconf, &print_node, step_stack, failures_only);
737 try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack, failures_only);
722738 }
723739 } else {
724740 if (s.dependencies.items.len == 0) {
......@@ -767,6 +783,7 @@ fn checkForDependencyLoop(
767783 .success => unreachable,
768784 .failure => unreachable,
769785 .skipped => unreachable,
786 .skipped_oom => unreachable,
770787 }
771788}
772789
......@@ -786,7 +803,7 @@ fn workerMakeOneStep(
786803 for (s.dependencies.items) |dep| {
787804 switch (@atomicLoad(Step.State, &dep.state, .SeqCst)) {
788805 .success, .skipped => continue,
789 .failure, .dependency_failure => {
806 .failure, .dependency_failure, .skipped_oom => {
790807 @atomicStore(Step.State, &s.state, .dependency_failure, .SeqCst);
791808 return;
792809 },
......@@ -979,6 +996,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
979996 \\ none Do not print the build summary
980997 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
981998 \\ --maxrss <bytes> Limit memory usage (default is to use available memory)
999 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
9821000 \\
9831001 \\Project-Specific Options:
9841002 \\
lib/std/Build/Step.zig+3
......@@ -70,6 +70,9 @@ pub const State = enum {
7070 /// This state indicates that the step did not complete, however, it also did not fail,
7171 /// and it is safe to continue executing its dependencies.
7272 skipped,
73 /// This step was skipped because it specified a max_rss that exceeded the runner's maximum.
74 /// It is not safe to run its dependencies.
75 skipped_oom,
7376};
7477
7578pub const Id = enum {