tiny.profiling.execute
Defined in tiny.profiling.
API (34)
Actions
Public operations.
Group.activeScope.directForScope.nameScope.parseawaitGroupUntilchildArgvcommandTextdeadlineNanosecondsenvironmentWithOverridesoptimizeBuildArgplanpollGroupputArtifactEnvrunChildrunCommandrunRecordedCommandspawnGroupstopGroupzig
Types and contracts
Public types and contracts.
ArtifactEnvBenchControlCommandResultGroupGroupIsolationGroupReceiptGroupStatusPlanResultScopeZig
Values and defaults
Public values and defaults.
Source
Source: src/profiling/execute.zig
zig
const std = @import("std");const sys = @import("sys");const catalog = @import("catalog.zig");const wait_poll_ms: u64 = 2;const maximum_grace_ms: u64 = 60_000;pub const default_termination_grace_ms: u64 = 100;pub const zig_env_var = "TINY_PROFILE_ZIG";pub const build_flag = "-fno-incremental";pub const Zig = struct { executable: []const u8,};pub const GroupStatus = enum { exited, stopped, timed_out,};pub const GroupIsolation = enum { child, process_group,};pub const GroupReceipt = struct { status: GroupStatus, isolation: GroupIsolation, pid: u64, term: ?sys.process.Termination, elapsed_ns: u64, terminate_sent: bool, kill_sent: bool,};pub const Group = struct { child: sys.process.Child, child_id: sys.process.Child.Id, started_monotonic_ns: i128, term: ?sys.process.Termination = null, isolation: GroupIsolation, pub fn active(self: *const Group) bool { return self.child.id != null; }};pub fn zig(environ_map: ?*const sys.process.Environ.Map) Zig { const env = environ_map orelse return .{ .executable = "zig" }; return .{ .executable = env.get(zig_env_var) orelse "zig", };}const test_zig: Zig = .{ .executable = "zig" };pub const default_optimize: std.builtin.OptimizeMode = .fast;pub fn optimizeBuildArg(mode: std.builtin.OptimizeMode) []const u8 { return switch (mode) { .debug => "-Doptimize=debug", .safe => "-Doptimize=safe", .fast => "-Doptimize=fast", .small => "-Doptimize=small", };}const retain_root_symbols_args = [_][]const u8{ "-Dproduct-strip-binaries=false", "-Dtool-strip-binaries=false",};pub const Result = struct { exit_code: i64, wall_ns: u64, resource_usage_source: ?sys.process.ResourceUsageSource = null, maxrss_kib: ?i64 = null, user_s: ?f64 = null, system_s: ?f64 = null, minor_page_faults: ?u64 = null, major_page_faults: ?u64 = null, voluntary_context_switches: ?u64 = null, involuntary_context_switches: ?u64 = null, pid: ?u64 = null,};pub const CommandResult = struct { command: []const u8, argv: []const []const u8, cwd: ?[]const u8, stdout_path: []const u8, stderr_path: []const u8, execution: Result,};pub const ArtifactEnv = struct { stdout: []const u8, stderr: []const u8, bench_jsonl: []const u8, coz_jsonl: []const u8, coz_analysis: []const u8, tracy_jsonl: []const u8, tracy_summary: []const u8, allocations: []const u8,};pub const Scope = enum { step, binary, mixed, pub fn parse(value: []const u8) ?Scope { if (std.mem.eql(u8, value, "step")) return .step; if (std.mem.eql(u8, value, "binary")) return .binary; if (std.mem.eql(u8, value, "mixed")) return .mixed; return null; } pub fn name(self: Scope) []const u8 { return @tagName(self); } pub fn directFor(self: Scope, workload: catalog.Workload) bool { return switch (self) { .step => false, .binary => true, .mixed => workload.requiresDirectExecution(), }; }};pub const Plan = struct { setup_argv: ?[]const []const u8 = null, argv: []const []const u8, cwd: ?[]const u8 = null, direct: bool = false, missing_bin: bool = false,};pub fn plan( allocator: std.mem.Allocator, zig_command: Zig, workload: catalog.Workload, forwarded: []const []const u8, direct: bool, build_args: []const []const u8,) !Plan { if (direct) { if (workload.bin) |bin| { const setup_scope = bin.scope(workload.package); const setup_argv = try buildArgv( allocator, zig_command, bin.step, build_args, workload.buildOptionsFor(setup_scope), isRootScope(setup_scope), &.{}, false, ); var argv: std.ArrayList([]const u8) = .empty; try argv.append(allocator, bin.path); try argv.appendSlice(allocator, bin.args); if (workload.forwards_args and forwarded.len != 0) try argv.appendSlice(allocator, forwarded); const scope = bin.scope(workload.package); return .{ .setup_argv = setup_argv, .argv = try argv.toOwnedSlice(allocator), .cwd = if (std.mem.eql(u8, scope, ".")) null else scope, .direct = true, }; } return .{ .argv = try childArgv(allocator, zig_command, workload, forwarded, build_args), .cwd = workload.cwd, .missing_bin = true, }; } return .{ .argv = try childArgv(allocator, zig_command, workload, forwarded, build_args), .cwd = workload.cwd, };}pub fn childArgv( allocator: std.mem.Allocator, zig_command: Zig, workload: catalog.Workload, forwarded: []const []const u8, build_args: []const []const u8,) ![]const []const u8 { const scope = workload.cwd orelse "."; return try buildArgv( allocator, zig_command, workload.step, build_args, workload.buildOptionsFor(scope), isRootScope(scope), forwarded, workload.forwards_args, );}fn buildArgv( allocator: std.mem.Allocator, zig_command: Zig, step: []const u8, build_args: []const []const u8, package_options: []const []const u8, root_build: bool, forwarded: []const []const u8, forwards_args: bool,) ![]const []const u8 { if (root_build) std.debug.assert(package_options.len == 0); const root_count: usize = if (root_build) retain_root_symbols_args.len else 0; const forwarded_count: usize = if (forwards_args and forwarded.len != 0) forwarded.len + 1 else 0; const argv = try allocator.alloc( []const u8, 4 + build_args.len + package_options.len + root_count + forwarded_count, ); argv[0] = zig_command.executable; argv[1] = "build"; argv[2] = build_flag; argv[3] = step; @memcpy(argv[4 .. 4 + build_args.len], build_args); var index = 4 + build_args.len; @memcpy(argv[index..][0..package_options.len], package_options); index += package_options.len; if (root_build) { @memcpy( argv[index..][0..retain_root_symbols_args.len], retain_root_symbols_args[0..], ); index += retain_root_symbols_args.len; } if (forwarded_count != 0) { argv[index] = "--"; index += 1; for (forwarded, 0..) |arg, forwarded_index| { argv[index + forwarded_index] = arg; } } return argv;}fn isRootScope(scope: []const u8) bool { return std.mem.eql(u8, scope, ".");}pub fn commandText(allocator: std.mem.Allocator, cwd: ?[]const u8, setup_argv: ?[]const []const u8, argv: []const []const u8) ![]const u8 { var out: std.Io.Writer.Allocating = .init(allocator); errdefer out.deinit(); const grouped = cwd != null or setup_argv != null; if (cwd) |path| { try out.writer.print("(cd {s} && ", .{path}); } else if (grouped) { try out.writer.writeByte('('); } if (setup_argv) |setup| { try writeArgv(&out.writer, setup); try out.writer.writeAll(" && "); } try writeArgv(&out.writer, argv); if (grouped) try out.writer.writeByte(')'); return try out.toOwnedSlice();}fn writeArgv(writer: *std.Io.Writer, argv: []const []const u8) !void { for (argv, 0..) |arg, index| { if (index != 0) try writer.writeByte(' '); try writer.writeAll(arg); }}pub const BenchControl = struct { causal: bool = false, min_time_ns: ?u64 = null, filter: ?[]const u8 = null,};pub fn environmentWithOverrides( allocator: std.mem.Allocator, base_env: ?*const sys.process.Environ.Map, overrides: []const catalog.EnvironmentOverride,) !sys.process.Environ.Map { try catalog.validateEnvironment(overrides); var result = if (base_env) |actual| try actual.clone(allocator) else sys.process.Environ.Map.init(allocator); errdefer result.deinit(); for (overrides) |entry| { if (entry.value) |value| { try result.put(entry.name, value); } else { _ = result.swapRemove(entry.name); } } return result;}pub fn spawnGroup( process_io: std.Io, options: sys.process.SpawnOptions,) !Group { std.debug.assert(options.argv.len != 0); var grouped_options = options; grouped_options.pgid = childProcessGroup(); const started_monotonic_ns = sys.time.nanoTimestamp(); var child = try sys.process.spawn(process_io, grouped_options); errdefer sys.process.killAndReap(&child, process_io); const child_id = child.id orelse return error.MissingChildProcessId; return .{ .child = child, .child_id = child_id, .started_monotonic_ns = started_monotonic_ns, .isolation = if (grouped_options.pgid == null) .child else .process_group, };}pub fn pollGroup(group: *Group) !?sys.process.Termination { std.debug.assert(group.active()); const outcome = (try sys.process.waitNoHang(group.child_id)) orelse return null; group.child.id = null; group.term = outcome.term; return outcome.term;}pub fn awaitGroupUntil( group: *Group, process_io: std.Io, deadline_monotonic_ns: i128, grace_ms: u64,) !GroupReceipt { std.debug.assert(group.active()); while (true) { if (sys.time.nanoTimestamp() >= deadline_monotonic_ns) { return stopGroupAs(group, process_io, grace_ms, .timed_out); } if (try pollGroup(group)) |_| { return groupReceipt(group, .exited, false, false); } sys.time.sleepMilliseconds(wait_poll_ms); }}pub fn stopGroup( group: *Group, process_io: std.Io, grace_ms: u64,) !GroupReceipt { return stopGroupAs(group, process_io, grace_ms, .stopped);}pub fn deadlineNanoseconds(start_monotonic_ns: i128, timeout_ms: u64) i128 { const timeout_ns = @as(i128, @intCast(timeout_ms)) * std.time.ns_per_ms; return start_monotonic_ns + timeout_ns;}fn stopGroupAs( group: *Group, process_io: std.Io, grace_ms: u64, status: GroupStatus,) !GroupReceipt { std.debug.assert(grace_ms <= maximum_grace_ms); if (!group.active()) { return groupReceipt(group, status, false, false); } if (group.isolation == .child) { return stopChildAs(group, process_io, grace_ms, status); } const terminate_sent = try signalGroup(group.child_id, .terminate); if (!terminate_sent) { group.term = try sys.process.wait(&group.child, process_io); return groupReceipt(group, status, false, false); } sys.time.sleepMilliseconds(grace_ms); const kill_sent = try signalGroup(group.child_id, .kill); group.term = try sys.process.wait(&group.child, process_io); return groupReceipt(group, status, true, kill_sent);}fn stopChildAs( group: *Group, process_io: std.Io, grace_ms: u64, status: GroupStatus,) !GroupReceipt { sys.process.requestTermination(&group.child, process_io); const deadline = deadlineNanoseconds(sys.time.nanoTimestamp(), grace_ms); while (sys.time.nanoTimestamp() < deadline) { if (try pollGroup(group)) |_| { return groupReceipt(group, status, true, false); } sys.time.sleepMilliseconds(wait_poll_ms); } sys.process.killAndReap(&group.child, process_io); return groupReceipt(group, status, true, true);}fn signalGroup( child_id: sys.process.Child.Id, signal: sys.process.ChildSignal,) !bool { sys.process.signalChildGroup(child_id, signal) catch |err| switch (err) { error.ProcessNotFound => return false, else => return err, }; return true;}fn groupReceipt( group: *const Group, status: GroupStatus, terminate_sent: bool, kill_sent: bool,) GroupReceipt { const finished_monotonic_ns = sys.time.nanoTimestamp(); return .{ .status = status, .isolation = group.isolation, .pid = @intCast(group.child_id), .term = group.term, .elapsed_ns = @intCast(@max( finished_monotonic_ns - group.started_monotonic_ns, 0, )), .terminate_sent = terminate_sent, .kill_sent = kill_sent, };}fn childProcessGroup() @TypeOf( @as(sys.process.SpawnOptions, undefined).pgid,) { return switch (comptime sys.process.childSignalPolicy()) { .unsupported => null, .linux_syscall, .posix_host => 0, };}pub fn runChild( allocator: std.mem.Allocator, process_io: std.Io, base_env: ?*const sys.process.Environ.Map, cwd: ?[]const u8, argv: []const []const u8, artifacts: ArtifactEnv, trace_allocations: bool, tracy: bool, control: BenchControl,) !Result { const stdout_file = try sys.fs.createFile(artifacts.stdout, .{ .truncate = true, .read = true }); defer sys.fs.closeHandle(stdout_file); const stderr_file = try sys.fs.createFile(artifacts.stderr, .{ .truncate = true, .read = true }); defer sys.fs.closeHandle(stderr_file); try resetArtifact(artifacts.bench_jsonl); try resetArtifact(artifacts.coz_jsonl); try resetArtifact(artifacts.coz_analysis); try resetArtifact(artifacts.tracy_jsonl); try resetArtifact(artifacts.tracy_summary); try resetArtifact(artifacts.allocations); var env = if (base_env) |actual| try actual.clone(allocator) else null; defer if (env) |*actual| actual.deinit(); if (env) |*actual| { try putArtifactEnv(actual, artifacts, trace_allocations, tracy, control); } const start = sys.time.nanoTimestamp(); var child = sys.process.spawn(process_io, .{ .argv = argv, .environ_map = if (env) |*actual| actual else null, .cwd = if (cwd) |path| .{ .path = path } else .inherit, .stdin = .inherit, .stdout = .{ .file = stdout_file }, .stderr = .{ .file = stderr_file }, .request_resource_usage_statistics = false, }) catch |err| { try writeSpawnFailure(stderr_file, err); return spawnFailureResult(start, err); }; errdefer sys.process.killAndReap(&child, process_io); const pid: u64 = @intCast(child.id orelse return error.MissingChildProcessId); return try awaitChild(process_io, &child, start, pid);}pub fn runCommand( process_io: std.Io, base_env: ?*const sys.process.Environ.Map, cwd: ?[]const u8, argv: []const []const u8, stdout_path: []const u8, stderr_path: []const u8,) !Result { const stdout_file = try sys.fs.createFile(stdout_path, .{ .truncate = true, .read = true }); defer sys.fs.closeHandle(stdout_file); const stderr_file = try sys.fs.createFile(stderr_path, .{ .truncate = true, .read = true }); defer sys.fs.closeHandle(stderr_file); const start = sys.time.nanoTimestamp(); var child = sys.process.spawn(process_io, .{ .argv = argv, .environ_map = base_env, .cwd = if (cwd) |path| .{ .path = path } else .inherit, .stdin = .inherit, .stdout = .{ .file = stdout_file }, .stderr = .{ .file = stderr_file }, .request_resource_usage_statistics = false, }) catch |err| { try writeSpawnFailure(stderr_file, err); return spawnFailureResult(start, err); }; errdefer sys.process.killAndReap(&child, process_io); const pid: u64 = @intCast(child.id orelse return error.MissingChildProcessId); return try awaitChild(process_io, &child, start, pid);}pub fn runRecordedCommand( allocator: std.mem.Allocator, process_io: std.Io, base_env: ?*const sys.process.Environ.Map, cwd: ?[]const u8, argv: []const []const u8, stdout_path: []const u8, stderr_path: []const u8,) !CommandResult { return .{ .command = try commandText(allocator, cwd, null, argv), .argv = argv, .cwd = cwd, .stdout_path = stdout_path, .stderr_path = stderr_path, .execution = try runCommand( process_io, base_env, cwd, argv, stdout_path, stderr_path, ), };}fn awaitChild( process_io: std.Io, child: *sys.process.Child, start: i128, pid: u64,) !Result { if (child.id) |child_pid| { while (true) { const outcome = try sys.process.waitNoHang(child_pid); if (outcome) |finished| { child.id = null; return resultFromTerm(start, pid, finished.term, finished.usage); } sys.time.sleepMilliseconds(wait_poll_ms); } } const term = try sys.process.wait(child, process_io); return resultFromTerm(start, pid, term, .{});}pub fn putArtifactEnv( env: *sys.process.Environ.Map, artifacts: ArtifactEnv, trace_allocations: bool, tracy: bool, control: BenchControl,) !void { try env.put("BENCH_JSONL", artifacts.bench_jsonl); try env.put("BENCH_COZ_JSONL", artifacts.coz_jsonl); try env.put("BENCH_COZ_ANALYSIS_JSON", artifacts.coz_analysis); try putOrScrub(env, "BENCH_TRACY_JSONL", if (tracy) artifacts.tracy_jsonl else null); try putOrScrub(env, "BENCH_TRACY_SUMMARY_JSONL", if (tracy) artifacts.tracy_summary else null); try putOrScrub(env, "TINY_PROFILE_ALLOCATIONS_PATH", if (trace_allocations) artifacts.allocations else null); try putOrScrub(env, "BENCH_COZ_EXPERIMENTS", if (control.causal) "1" else null); var min_time_buffer: [20]u8 = undefined; const min_time_text: ?[]const u8 = if (control.min_time_ns) |ns| std.fmt.bufPrint(&min_time_buffer, "{d}", .{ns}) catch unreachable else null; try putOrScrub(env, "BENCH_MIN_TIME_NS", min_time_text); try putOrScrub(env, "BENCH_FILTER", control.filter);}fn putOrScrub(env: *sys.process.Environ.Map, key: []const u8, value: ?[]const u8) !void { if (value) |actual| { try env.put(key, actual); } else { _ = env.swapRemove(key); }}fn resetArtifact(path: []const u8) !void { const file = try sys.fs.createFile(path, .{ .truncate = true }); sys.fs.closeHandle(file);}fn resultFromTerm( start_ns: i128, pid: ?u64, term: sys.process.Termination, usage: sys.process.ResourceUsage,) Result { const end_ns = sys.time.nanoTimestamp(); const wall_ns: u64 = @intCast(@max(end_ns - start_ns, 0)); return .{ .pid = pid, .exit_code = sys.process.exitCode(term), .wall_ns = wall_ns, .resource_usage_source = usage.source, .maxrss_kib = usage.maxrss_kib, .user_s = usage.user_s, .system_s = usage.system_s, .minor_page_faults = usage.minor_page_faults, .major_page_faults = usage.major_page_faults, .voluntary_context_switches = usage.voluntary_context_switches, .involuntary_context_switches = usage.involuntary_context_switches, };}fn writeSpawnFailure(file: std.Io.File, err: anyerror) !void { var buffer: [256]u8 = undefined; var writer = file.writer(sys.fs.debugIo(), &buffer); try writer.interface.print("spawn failed: {s}\n", .{@errorName(err)}); try writer.interface.flush();}fn spawnFailureResult(start_ns: i128, err: anyerror) Result { const end_ns = sys.time.nanoTimestamp(); return .{ .exit_code = spawnFailureExitCode(err), .wall_ns = @intCast(@max(end_ns - start_ns, 0)), };}fn spawnFailureExitCode(err: anyerror) i64 { return switch (err) { error.AccessDenied => 126, else => 127, };}test "profiling execution builds child argv with forwarded args only when supported" { const allocator = std.testing.allocator; const forwarded = &.{ "--test-filter", "x" }; const with_forwarding = try childArgv( allocator, test_zig, catalog.find("choir.compiler").?, forwarded, &.{"-Doptimize=fast"}, ); defer allocator.free(with_forwarding); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "choir-compiler-bench", "-Doptimize=fast", retain_root_symbols_args[0], retain_root_symbols_args[1], "--", "--test-filter", "x", }, with_forwarding, ); const without_forwarding = try childArgv( allocator, test_zig, catalog.find("gpalloc.allocator").?, forwarded, &.{"-Doptimize=fast"}, ); defer allocator.free(without_forwarding); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "gpalloc-bench", "-Doptimize=fast", retain_root_symbols_args[0], retain_root_symbols_args[1], }, without_forwarding, );}test "profiling execution resolves the invoking Zig build command from the environment" { const allocator = std.testing.allocator; var env = sys.process.Environ.Map.init(allocator); defer env.deinit(); try std.testing.expectEqualStrings("zig", zig(null).executable); try std.testing.expectEqualStrings("zig", zig(&env).executable); try env.put(zig_env_var, "/opt/zig/zig"); try std.testing.expectEqualStrings("/opt/zig/zig", zig(&env).executable); const argv = try childArgv( allocator, zig(&env), catalog.find("gpalloc.allocator").?, &.{}, &.{"-Doptimize=fast"}, ); defer allocator.free(argv); try std.testing.expectEqualStrings("/opt/zig/zig", argv[0]); try std.testing.expectEqualStrings("-fno-incremental", argv[2]);}test "profiling execution formats cwd commands" { const allocator = std.testing.allocator; const workload = catalog.find("gpalloc.driver").?; const argv = try childArgv( allocator, test_zig, workload, &.{}, &.{"-Doptimize=safe"}, ); defer allocator.free(argv); const text = try commandText(allocator, workload.cwd, null, argv); defer allocator.free(text); try std.testing.expectEqualStrings( "(cd lib/gpalloc && zig build -fno-incremental bench-driver -Doptimize=safe)", text, );}test "profiling execution gives package build options only to package-scoped builds" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const arena = arena_state.allocator(); const opt_in = catalog.find("tldr.linker").?; try std.testing.expectEqualSlices([]const u8, &.{"-Dprofiling=true"}, opt_in.package_build_options); const root_step = try plan(arena, test_zig, opt_in, &.{}, false, &.{"-Doptimize=fast"}); try std.testing.expect(root_step.cwd == null); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "tldr-bench", "-Doptimize=fast", retain_root_symbols_args[0], retain_root_symbols_args[1], }, root_step.argv, ); const direct = try plan(arena, test_zig, opt_in, &.{}, true, &.{"-Doptimize=fast"}); try std.testing.expectEqualStrings("lib/tldr", direct.cwd.?); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "bench-bin", "-Doptimize=fast", "-Dprofiling=true" }, direct.setup_argv.?, ); const default = catalog.find("gpalloc.allocator").?; try std.testing.expectEqual(@as(usize, 0), default.package_build_options.len); const default_direct = try plan(arena, test_zig, default, &.{}, true, &.{"-Doptimize=fast"}); try std.testing.expectEqualStrings("lib/gpalloc", default_direct.cwd.?); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "bench-bin", "-Doptimize=fast" }, default_direct.setup_argv.?, ); var local = opt_in; local.bin = null; local.cwd = opt_in.package; local.step = opt_in.localStep(); const local_step = try plan(arena, test_zig, local, &.{}, false, &.{}); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "bench", "-Dprofiling=true" }, local_step.argv, );}test "profiling execution scope parses user names" { try std.testing.expectEqual(Scope.step, Scope.parse("step").?); try std.testing.expectEqual(Scope.binary, Scope.parse("binary").?); try std.testing.expectEqual(Scope.mixed, Scope.parse("mixed").?); try std.testing.expect(Scope.parse("whole-step") == null); const ordinary_binary = catalog.find("mprompt.smoke").?; const ordinary_step = catalog.find("choir.versus").?; const configured = catalog.Workload{ .name = "configured", .package = "fixture", .step = "fixture-test", .summary = "direct execution fixture", .tier = .smoke, .surface = .benchmark, .environment = &.{.{ .name = "FIXTURE_DIRECT", .value = "1" }}, }; try std.testing.expect(!Scope.step.directFor(ordinary_binary)); try std.testing.expect(Scope.binary.directFor(ordinary_binary)); try std.testing.expect(!Scope.mixed.directFor(ordinary_binary)); try std.testing.expect(!Scope.mixed.directFor(ordinary_step)); try std.testing.expect(Scope.mixed.directFor(configured)); try std.testing.expectEqualStrings( "-Doptimize=small", optimizeBuildArg(.small), );}test "profiling execution formats setup phases into command text" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const setup = [_][]const u8{ "zig", "build", "-fno-incremental", "bench-bin" }; const argv = [_][]const u8{ "zig-out/bin/mprompt-bench", "--workers", "128" }; const text = try commandText(allocator, "lib/mprompt", &setup, &argv); try std.testing.expectEqualStrings("(cd lib/mprompt && zig build -fno-incremental bench-bin && zig-out/bin/mprompt-bench --workers 128)", text);}test "profiling execution plans direct workloads through their binaries" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const workload = catalog.Workload{ .name = "example.bench", .package = "lib/example", .step = "example-bench", .summary = "example", .tier = .smoke, .surface = .benchmark, .forwards_args = true, .bin = .{ .path = "zig-out/bin/example-bench", .args = &.{"--count"} }, }; const direct = try plan( allocator, .{ .executable = "/opt/zig/zig" }, workload, &.{}, true, &.{ "-Doptimize=fast", "-Dcpu=x86_64_v3" }, ); try std.testing.expect(direct.direct); try std.testing.expect(!direct.missing_bin); try std.testing.expectEqualStrings("lib/example", direct.cwd.?); try std.testing.expectEqualSlices( []const u8, &.{ "/opt/zig/zig", "build", "-fno-incremental", "bench-bin", "-Doptimize=fast", "-Dcpu=x86_64_v3", }, direct.setup_argv.?, ); try std.testing.expectEqualSlices([]const u8, &.{ "zig-out/bin/example-bench", "--count" }, direct.argv); const forwarded = try plan(allocator, test_zig, workload, &.{"--fast"}, true, &.{}); try std.testing.expectEqualSlices([]const u8, &.{ "zig-out/bin/example-bench", "--count", "--fast" }, forwarded.argv); const whole_step = try plan( allocator, test_zig, workload, &.{}, false, &.{"-Doptimize=fast"}, ); try std.testing.expect(!whole_step.direct); try std.testing.expect(whole_step.setup_argv == null); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "example-bench", "-Doptimize=fast", retain_root_symbols_args[0], retain_root_symbols_args[1], }, whole_step.argv, );}test "profiling execution plans root-scoped binaries at the repository root" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const workload = catalog.Workload{ .name = "example.rooted", .package = "lib/example", .step = "example-bench", .summary = "example", .tier = .smoke, .surface = .benchmark, .bin = .{ .step = "example-bench-bin", .path = "zig-out/bin/example-bench", .cwd = "." }, }; const direct = try plan( allocator, test_zig, workload, &.{}, true, &.{"-Doptimize=small"}, ); try std.testing.expect(direct.direct); try std.testing.expect(direct.cwd == null); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "example-bench-bin", "-Doptimize=small", retain_root_symbols_args[0], retain_root_symbols_args[1], }, direct.setup_argv.?, ); try std.testing.expectEqualSlices([]const u8, &.{"zig-out/bin/example-bench"}, direct.argv);}test "profiling execution marks direct plans without binaries" { var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const workload = catalog.Workload{ .name = "example.nobin", .package = "lib/example", .step = "example-bench", .summary = "example", .tier = .smoke, .surface = .benchmark, }; const planned = try plan( allocator, test_zig, workload, &.{}, true, &.{"-Doptimize=fast"}, ); try std.testing.expect(planned.missing_bin); try std.testing.expect(!planned.direct); try std.testing.expect(planned.setup_argv == null); try std.testing.expectEqualSlices( []const u8, &.{ "zig", "build", "-fno-incremental", "example-bench", "-Doptimize=fast", retain_root_symbols_args[0], retain_root_symbols_args[1], }, planned.argv, );}test "profiling execution only exports requested in-process trace paths" { const allocator = std.testing.allocator; const artifacts = ArtifactEnv{ .stdout = "stdout.txt", .stderr = "stderr.txt", .bench_jsonl = "bench.jsonl", .coz_jsonl = "bench.coz.jsonl", .coz_analysis = "bench.coz.analysis.json", .tracy_jsonl = "bench.tracy.jsonl", .tracy_summary = "bench.tracy.summary.jsonl", .allocations = "allocations.jsonl", }; var default_env = sys.process.Environ.Map.init(allocator); defer default_env.deinit(); try putArtifactEnv(&default_env, artifacts, false, false, .{}); try std.testing.expect(default_env.get("BENCH_COZ_EXPERIMENTS") == null); try std.testing.expectEqualStrings("bench.jsonl", default_env.get("BENCH_JSONL").?); try std.testing.expect(default_env.get("BENCH_TRACY_JSONL") == null); try std.testing.expect(default_env.get("TINY_PROFILE_ALLOCATIONS_PATH") == null); var trace_env = sys.process.Environ.Map.init(allocator); defer trace_env.deinit(); try putArtifactEnv(&trace_env, artifacts, true, true, .{ .causal = true }); try std.testing.expectEqualStrings("1", trace_env.get("BENCH_COZ_EXPERIMENTS").?); try std.testing.expectEqualStrings("allocations.jsonl", trace_env.get("TINY_PROFILE_ALLOCATIONS_PATH").?); try std.testing.expectEqualStrings("bench.tracy.jsonl", trace_env.get("BENCH_TRACY_JSONL").?); try std.testing.expectEqualStrings("bench.tracy.summary.jsonl", trace_env.get("BENCH_TRACY_SUMMARY_JSONL").?); try std.testing.expect(trace_env.get("BENCH_MIN_TIME_NS") == null); try std.testing.expect(trace_env.get("BENCH_FILTER") == null);}test "profiling execution exports benchmark controls" { const allocator = std.testing.allocator; const artifacts = ArtifactEnv{ .stdout = "stdout.txt", .stderr = "stderr.txt", .bench_jsonl = "bench.jsonl", .coz_jsonl = "bench.coz.jsonl", .coz_analysis = "bench.coz.analysis.json", .tracy_jsonl = "bench.tracy.jsonl", .tracy_summary = "bench.tracy.summary.jsonl", .allocations = "allocations.jsonl", }; var env = sys.process.Environ.Map.init(allocator); defer env.deinit(); try putArtifactEnv(&env, artifacts, false, false, .{ .causal = true, .min_time_ns = 30_000_000_000, .filter = "small alloc", }); try std.testing.expectEqualStrings("1", env.get("BENCH_COZ_EXPERIMENTS").?); try std.testing.expectEqualStrings("30000000000", env.get("BENCH_MIN_TIME_NS").?); try std.testing.expectEqualStrings("small alloc", env.get("BENCH_FILTER").?);}test "profiling execution scrubs stale bench control variables from the parent" { const allocator = std.testing.allocator; const artifacts = ArtifactEnv{ .stdout = "stdout.txt", .stderr = "stderr.txt", .bench_jsonl = "bench.jsonl", .coz_jsonl = "bench.coz.jsonl", .coz_analysis = "bench.coz.analysis.json", .tracy_jsonl = "bench.tracy.jsonl", .tracy_summary = "bench.tracy.summary.jsonl", .allocations = "allocations.jsonl", }; var env = sys.process.Environ.Map.init(allocator); defer env.deinit(); try env.put("BENCH_COZ_EXPERIMENTS", "1"); try env.put("BENCH_MIN_TIME_NS", "30000000000"); try env.put("BENCH_FILTER", "small alloc"); try env.put("BENCH_TRACY_JSONL", "stale.tracy.jsonl"); try env.put("BENCH_TRACY_SUMMARY_JSONL", "stale.tracy.summary.jsonl"); try env.put("TINY_PROFILE_ALLOCATIONS_PATH", "stale.jsonl"); try putArtifactEnv(&env, artifacts, false, false, .{}); try std.testing.expect(env.get("BENCH_COZ_EXPERIMENTS") == null); try std.testing.expect(env.get("BENCH_MIN_TIME_NS") == null); try std.testing.expect(env.get("BENCH_FILTER") == null); try std.testing.expect(env.get("BENCH_TRACY_JSONL") == null); try std.testing.expect(env.get("BENCH_TRACY_SUMMARY_JSONL") == null); try std.testing.expect(env.get("TINY_PROFILE_ALLOCATIONS_PATH") == null);}test "profiling execution applies bounded set and unset child environment overrides" { const allocator = std.testing.allocator; var parent = sys.process.Environ.Map.init(allocator); defer parent.deinit(); try parent.put("HOME", "/parent"); try parent.put("FIXTURE_OBSERVATION_PATH", "/stale"); try parent.put("KEPT", "yes"); var child = try environmentWithOverrides(allocator, &parent, &.{ .{ .name = "HOME", .value = "/fixture" }, .{ .name = "FIXTURE_OBSERVATION_PATH" }, }); defer child.deinit(); try std.testing.expectEqualStrings("/fixture", child.get("HOME").?); try std.testing.expect(child.get("FIXTURE_OBSERVATION_PATH") == null); try std.testing.expectEqualStrings("yes", child.get("KEPT").?); try std.testing.expectEqualStrings("/parent", parent.get("HOME").?); try std.testing.expectEqualStrings( "/stale", parent.get("FIXTURE_OBSERVATION_PATH").?, );}test "profiling execution records child spawn failures" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const root = try std.fs.path.join(allocator, &.{ ".zig-cache", "tmp", tmp.sub_path[0..] }); const artifacts = ArtifactEnv{ .stdout = try std.fs.path.join(allocator, &.{ root, "stdout.txt" }), .stderr = try std.fs.path.join(allocator, &.{ root, "stderr.txt" }), .bench_jsonl = try std.fs.path.join(allocator, &.{ root, "bench.jsonl" }), .coz_jsonl = try std.fs.path.join(allocator, &.{ root, "bench.coz.jsonl" }), .coz_analysis = try std.fs.path.join(allocator, &.{ root, "bench.coz.analysis.json" }), .tracy_jsonl = try std.fs.path.join(allocator, &.{ root, "bench.tracy.jsonl" }), .tracy_summary = try std.fs.path.join(allocator, &.{ root, "bench.tracy.summary.jsonl" }), .allocations = try std.fs.path.join(allocator, &.{ root, "allocations.jsonl" }), }; const result = try runChild( allocator, std.testing.io, null, null, &.{"definitely-missing-tiny-profile-child"}, artifacts, false, false, .{}, ); try std.testing.expectEqual(@as(i64, 127), result.exit_code); try std.testing.expect(result.pid == null); const stderr = try sys.fs.readFileAlloc(allocator, artifacts.stderr, 4096); try std.testing.expect(std.mem.indexOf(u8, stderr, "spawn failed:") != null);}test "profiling execution records the waited child PID" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena_state.deinit(); const allocator = arena_state.allocator(); const root = try tmp.parent_dir.realPathFileAlloc( std.testing.io, tmp.sub_path[0..], allocator, ); const stdout_path = try std.fs.path.join(allocator, &.{ root, "stdout.txt" }); const stderr_path = try std.fs.path.join(allocator, &.{ root, "stderr.txt" }); const execution = try runCommand( std.testing.io, null, null, &.{"/bin/true"}, stdout_path, stderr_path, ); try std.testing.expect((execution.pid orelse 0) > 0); try std.testing.expectEqual(@as(i64, 0), execution.exit_code);}test "profiling execution result retains an explicit process identity" { const result = resultFromTerm( 0, 42, .{ .exited = 0 }, .{}, ); try std.testing.expectEqual(@as(?u64, 42), result.pid);}test "profiling execution returns a completed process group receipt" { var group = try spawnGroup(std.testing.io, .{ .argv = &.{"/bin/true"}, .stdin = .ignore, .stdout = .ignore, .stderr = .ignore, }); const receipt = try awaitGroupUntil( &group, std.testing.io, deadlineNanoseconds(sys.time.nanoTimestamp(), 1_000), 10, ); try std.testing.expectEqual(GroupStatus.exited, receipt.status); try std.testing.expectEqual(GroupIsolation.process_group, receipt.isolation); try std.testing.expectEqual(@as(i64, 0), sys.process.exitCode(receipt.term.?)); try std.testing.expect(!receipt.terminate_sent); try std.testing.expect(!receipt.kill_sent); try expectProcessGone(@intCast(receipt.pid));}test "profiling execution times out and reaps its process group" { var group = try spawnGroup(std.testing.io, .{ .argv = &.{ "/bin/sh", "-c", "trap '' TERM; while :; do :; done" }, .stdin = .ignore, .stdout = .ignore, .stderr = .ignore, }); const receipt = try awaitGroupUntil( &group, std.testing.io, deadlineNanoseconds(sys.time.nanoTimestamp(), 20), 10, ); try std.testing.expectEqual(GroupStatus.timed_out, receipt.status); try std.testing.expectEqual(GroupIsolation.process_group, receipt.isolation); try std.testing.expect(receipt.terminate_sent); try std.testing.expect(receipt.kill_sent); try std.testing.expect(receipt.term != null); try expectProcessGone(@intCast(receipt.pid));}test "profiling execution timeout stops a resistant descendant" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); const allocator = std.testing.allocator; const root = try tmp.parent_dir.realPathFileAlloc( std.testing.io, tmp.sub_path[0..], allocator, ); defer allocator.free(root); const pid_path = try std.fs.path.join(allocator, &.{ root, "descendant.pid" }); defer allocator.free(pid_path); var group = try spawnGroup(std.testing.io, .{ .argv = &.{ "/bin/sh", "-c", "trap '' TERM; /bin/sh -c \"trap '' TERM; while :; do :; done\" & " ++ "echo $! > \"$1\"; wait", "tiny-process-group-fixture", pid_path, }, .stdin = .ignore, .stdout = .ignore, .stderr = .ignore, }); defer if (group.active()) { _ = stopGroup(&group, std.testing.io, 10) catch {}; }; try waitForPath(pid_path); const receipt = try awaitGroupUntil( &group, std.testing.io, deadlineNanoseconds(sys.time.nanoTimestamp(), 20), 20, ); try std.testing.expectEqual(GroupStatus.timed_out, receipt.status); try std.testing.expect(receipt.kill_sent); const pid_text = try sys.fs.readFileAlloc(allocator, pid_path, 64); defer allocator.free(pid_text); const descendant_pid = try std.fmt.parseInt( sys.process.ProcessId, std.mem.trim(u8, pid_text, " \t\r\n"), 10, ); try expectProcessExited(descendant_pid); try expectProcessGone(@intCast(receipt.pid));}/// An orphan's adopting supervisor owns reaping its zombie entry.fn expectProcessExited(process_id: sys.process.ProcessId) !void { std.debug.assert(process_id > 0); for (0..100) |_| { const observed = sys.process.inspect.info(process_id) catch |err| switch (err) { error.ProcessNotFound => return, else => return err, }; if (!observed.alive) return; sys.time.sleepMilliseconds(5); } return error.TestExpectedProcessExit;}fn waitForPath(path: []const u8) !void { std.debug.assert(path.len != 0); var attempt: u8 = 0; while (attempt < 200) : (attempt += 1) { if (sys.fs.exists(path)) return; sys.time.sleepMilliseconds(5); } return error.ProcessFixtureDidNotStart;}fn expectProcessGone(process_id: sys.process.ProcessId) !void { std.debug.assert(process_id > 0); var attempt: u8 = 0; while (attempt < 100) : (attempt += 1) { if (!try sys.process.processAlive(process_id)) return; sys.time.sleepMilliseconds(5); } try std.testing.expect(false);}Source: src/profiling/root.zig:24
zig
pub const execute = @import("execute.zig");Complete caller list for execute.commandText
11 direct callers.
src.profiling.command.planRunDryRunWorkload[function] — private; no exact target atsrc/profiling/command.zig:754in nearest public ownertiny.profiling.commandsrc.profiling.command.writeRunDryRunWorkload[function] — private; no exact target atsrc/profiling/command.zig:811in nearest public ownertiny.profiling.commandtiny.profiling.driver.prepare.prepareWorkload[function] atsrc/profiling/driver/prepare.zig:23src.profiling.driver.prepare.runSetup[function] — private; no exact target atsrc/profiling/driver/prepare.zig:85in nearest public ownertiny.profiling.driver.preparetiny.profiling.execute.runRecordedCommand[function] atsrc/profiling/execute.zig:531src.profiling.execute.test_profiling_execution_formats_cwd_commands[function] — test; no exact target atsrc/profiling/execute.zig:733in nearest public ownertiny.profiling.executesrc.profiling.execute.test_profiling_execution_formats_setup_phases_into_command_text[function] — test; no exact target atsrc/profiling/execute.zig:832in nearest public ownertiny.profiling.executesrc.profiling.experiment.acquire.Runner.captureMeasurement[method] — private; no exact target atsrc/profiling/experiment/acquire.zig:326in nearest public ownertiny.profiling.experiment.acquiresrc.profiling.experiment.acquire.failedResetObservation[function] — private; no exact target atsrc/profiling/experiment/acquire.zig:396in nearest public ownertiny.profiling.experiment.acquiresrc.profiling.experiment.acquire.runOptionalCommand[function] — private; no exact target atsrc/profiling/experiment/acquire.zig:502in nearest public ownertiny.profiling.experiment.acquiresrc.profiling.experiment.variant.buildRef[function] — private; no exact target atsrc/profiling/experiment/variant.zig:154in nearest public ownertiny.profiling.experiment.variant
Complete caller list for execute.runCommand
7 direct callers.
src.profiling.driver.prepare.runSetup[function] — private; no exact target atsrc/profiling/driver/prepare.zig:85in nearest public ownertiny.profiling.driver.preparetiny.profiling.execute.runRecordedCommand[function] atsrc/profiling/execute.zig:531src.profiling.execute.test_profiling_execution_records_the_waited_child_PID[function] — test; no exact target atsrc/profiling/execute.zig:1132in nearest public ownertiny.profiling.executesrc.profiling.experiment.acquire.Runner.captureMeasurement[method] — private; no exact target atsrc/profiling/experiment/acquire.zig:326in nearest public ownertiny.profiling.experiment.acquiresrc.profiling.experiment.acquire.runOptionalCommand[function] — private; no exact target atsrc/profiling/experiment/acquire.zig:502in nearest public ownertiny.profiling.experiment.acquiresrc.profiling.experiment.variant.addWorktree[function] — private; no exact target atsrc/profiling/experiment/variant.zig:257in nearest public ownertiny.profiling.experiment.variantsrc.profiling.experiment.variant.buildRef[function] — private; no exact target atsrc/profiling/experiment/variant.zig:154in nearest public ownertiny.profiling.experiment.variant
Audit
| Definitions | 35 |
|---|---|
| Public names | 35 |
| Members | 54 |
| Version | 26.7.0 |
| Revision | daab053ee433 |