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 {...@@ -93,6 +93,7 @@ pub fn main() !void {
93 var dir_list = std.Build.DirList{};93 var dir_list = std.Build.DirList{};
94 var summary: ?Summary = null;94 var summary: ?Summary = null;
95 var max_rss: usize = 0;95 var max_rss: usize = 0;
96 var skip_oom_steps: bool = false;
96 var color: Color = .auto;97 var color: Color = .auto;
9798
98 const stderr_stream = io.getStdErr().writer();99 const stderr_stream = io.getStdErr().writer();
...@@ -158,6 +159,8 @@ pub fn main() !void {...@@ -158,6 +159,8 @@ pub fn main() !void {
158 });159 });
159 process.exit(1);160 process.exit(1);
160 };161 };
162 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
163 skip_oom_steps = true;
161 } else if (mem.eql(u8, arg, "--search-prefix")) {164 } else if (mem.eql(u8, arg, "--search-prefix")) {
162 const search_prefix = nextArg(args, &arg_idx) orelse {165 const search_prefix = nextArg(args, &arg_idx) orelse {
163 std.debug.print("Expected argument after {s}\n\n", .{arg});166 std.debug.print("Expected argument after {s}\n\n", .{arg});
...@@ -305,6 +308,7 @@ pub fn main() !void {...@@ -305,6 +308,7 @@ pub fn main() !void {
305 .max_rss = max_rss,308 .max_rss = max_rss,
306 .max_rss_is_default = false,309 .max_rss_is_default = false,
307 .max_rss_mutex = .{},310 .max_rss_mutex = .{},
311 .skip_oom_steps = skip_oom_steps,
308 .memory_blocked_steps = std.ArrayList(*Step).init(arena),312 .memory_blocked_steps = std.ArrayList(*Step).init(arena),
309313
310 .claimed_rss = 0,314 .claimed_rss = 0,
...@@ -335,6 +339,7 @@ const Run = struct {...@@ -335,6 +339,7 @@ const Run = struct {
335 max_rss: usize,339 max_rss: usize,
336 max_rss_is_default: bool,340 max_rss_is_default: bool,
337 max_rss_mutex: std.Thread.Mutex,341 max_rss_mutex: std.Thread.Mutex,
342 skip_oom_steps: bool,
338 memory_blocked_steps: std.ArrayList(*Step),343 memory_blocked_steps: std.ArrayList(*Step),
339344
340 claimed_rss: usize,345 claimed_rss: usize,
...@@ -383,10 +388,14 @@ fn runStepNames(...@@ -383,10 +388,14 @@ fn runStepNames(
383 for (step_stack.keys()) |s| {388 for (step_stack.keys()) |s| {
384 if (s.max_rss == 0) continue;389 if (s.max_rss == 0) continue;
385 if (s.max_rss > run.max_rss) {390 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", .{391 if (run.skip_oom_steps) {
387 s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,392 s.state = .skipped_oom;
388 });393 } else {
389 any_problems = true;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 }
390 }399 }
391 }400 }
392 if (any_problems) {401 if (any_problems) {
...@@ -416,6 +425,7 @@ fn runStepNames(...@@ -416,6 +425,7 @@ fn runStepNames(
416 const steps_slice = step_stack.keys();425 const steps_slice = step_stack.keys();
417 for (0..steps_slice.len) |i| {426 for (0..steps_slice.len) |i| {
418 const step = steps_slice[steps_slice.len - i - 1];427 const step = steps_slice[steps_slice.len - i - 1];
428 if (step.state == .skipped_oom) continue;
419429
420 wait_group.start();430 wait_group.start();
421 thread_pool.spawn(workerMakeOneStep, .{431 thread_pool.spawn(workerMakeOneStep, .{
...@@ -461,7 +471,7 @@ fn runStepNames(...@@ -461,7 +471,7 @@ fn runStepNames(
461 },471 },
462 .dependency_failure => pending_count += 1,472 .dependency_failure => pending_count += 1,
463 .success => success_count += 1,473 .success => success_count += 1,
464 .skipped => skipped_count += 1,474 .skipped, .skipped_oom => skipped_count += 1,
465 .failure => {475 .failure => {
466 failure_count += 1;476 failure_count += 1;
467 const compile_errors_len = s.result_error_bundle.errorMessageCount();477 const compile_errors_len = s.result_error_bundle.errorMessageCount();
...@@ -506,7 +516,7 @@ fn runStepNames(...@@ -506,7 +516,7 @@ fn runStepNames(
506 var print_node: PrintNode = .{ .parent = null };516 var print_node: PrintNode = .{ .parent = null };
507 if (step_names.len == 0) {517 if (step_names.len == 0) {
508 print_node.last = true;518 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 {};
510 } else {520 } else {
511 const last_index = if (!failures_only) b.top_level_steps.count() else blk: {521 const last_index = if (!failures_only) b.top_level_steps.count() else blk: {
512 var i: usize = step_names.len;522 var i: usize = step_names.len;
...@@ -519,7 +529,7 @@ fn runStepNames(...@@ -519,7 +529,7 @@ fn runStepNames(
519 for (step_names, 0..) |step_name, i| {529 for (step_names, 0..) |step_name, i| {
520 const tls = b.top_level_steps.get(step_name).?;530 const tls = b.top_level_steps.get(step_name).?;
521 print_node.last = i + 1 == last_index;531 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 {};
523 }533 }
524 }534 }
525 }535 }
...@@ -567,6 +577,7 @@ fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.io.tty.Config...@@ -567,6 +577,7 @@ fn printPrefix(node: *PrintNode, stderr: std.fs.File, ttyconf: std.io.tty.Config
567fn printTreeStep(577fn printTreeStep(
568 b: *std.Build,578 b: *std.Build,
569 s: *Step,579 s: *Step,
580 run: *const Run,
570 stderr: std.fs.File,581 stderr: std.fs.File,
571 ttyconf: std.io.tty.Config,582 ttyconf: std.io.tty.Config,
572 parent_node: *PrintNode,583 parent_node: *PrintNode,
...@@ -654,13 +665,18 @@ fn printTreeStep(...@@ -654,13 +665,18 @@ fn printTreeStep(
654 }665 }
655 try stderr.writeAll("\n");666 try stderr.writeAll("\n");
656 },667 },
657668 .skipped, .skipped_oom => |skip| {
658 .skipped => {
659 try ttyconf.setColor(stderr, .yellow);669 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");
661 try ttyconf.setColor(stderr, .reset);678 try ttyconf.setColor(stderr, .reset);
662 },679 },
663
664 .failure => {680 .failure => {
665 if (s.result_error_bundle.errorMessageCount() > 0) {681 if (s.result_error_bundle.errorMessageCount() > 0) {
666 try ttyconf.setColor(stderr, .red);682 try ttyconf.setColor(stderr, .red);
...@@ -718,7 +734,7 @@ fn printTreeStep(...@@ -718,7 +734,7 @@ fn printTreeStep(
718 .parent = parent_node,734 .parent = parent_node,
719 .last = i == last_index,735 .last = i == last_index,
720 };736 };
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);
722 }738 }
723 } else {739 } else {
724 if (s.dependencies.items.len == 0) {740 if (s.dependencies.items.len == 0) {
...@@ -767,6 +783,7 @@ fn checkForDependencyLoop(...@@ -767,6 +783,7 @@ fn checkForDependencyLoop(
767 .success => unreachable,783 .success => unreachable,
768 .failure => unreachable,784 .failure => unreachable,
769 .skipped => unreachable,785 .skipped => unreachable,
786 .skipped_oom => unreachable,
770 }787 }
771}788}
772789
...@@ -786,7 +803,7 @@ fn workerMakeOneStep(...@@ -786,7 +803,7 @@ fn workerMakeOneStep(
786 for (s.dependencies.items) |dep| {803 for (s.dependencies.items) |dep| {
787 switch (@atomicLoad(Step.State, &dep.state, .SeqCst)) {804 switch (@atomicLoad(Step.State, &dep.state, .SeqCst)) {
788 .success, .skipped => continue,805 .success, .skipped => continue,
789 .failure, .dependency_failure => {806 .failure, .dependency_failure, .skipped_oom => {
790 @atomicStore(Step.State, &s.state, .dependency_failure, .SeqCst);807 @atomicStore(Step.State, &s.state, .dependency_failure, .SeqCst);
791 return;808 return;
792 },809 },
...@@ -979,6 +996,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi...@@ -979,6 +996,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
979 \\ none Do not print the build summary996 \\ none Do not print the build summary
980 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)997 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
981 \\ --maxrss <bytes> Limit memory usage (default is to use available memory)998 \\ --maxrss <bytes> Limit memory usage (default is to use available memory)
999 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
982 \\1000 \\
983 \\Project-Specific Options:1001 \\Project-Specific Options:
984 \\1002 \\
lib/std/Build/Step.zig+3
...@@ -70,6 +70,9 @@ pub const State = enum {...@@ -70,6 +70,9 @@ pub const State = enum {
70 /// This state indicates that the step did not complete, however, it also did not fail,70 /// This state indicates that the step did not complete, however, it also did not fail,
71 /// and it is safe to continue executing its dependencies.71 /// and it is safe to continue executing its dependencies.
72 skipped,72 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,
73};76};
7477
75pub const Id = enum {78pub const Id = enum {