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