| ... | @@ -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; |
| 97 | | 98 | |
| 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), |
| 309 | | 313 | |
| 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), |
| 339 | | 344 | |
| 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; |
| 419 | | 429 | |
| 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 |
| 567 | fn printTreeStep( | 577 | fn 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 | }, |
| 657 | | 668 | .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 | } |
| 772 | | 789 | |
| ... | @@ -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 summary | 996 | \\ 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 | \\ |