Skip to documentation
SLOP

tiny.profiling.iteration.run

Reference tiny.profiling iteration run

Defined in iteration.

API (3)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsiterationrun
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsprivate; no linksrc.profiling.commandrunIterationenvironmentcollectfingerprintinspecthost.statecaptureprivate; no linksrc.profiling.iteration.run.PhaseClockstartprivate; no linksrc.profiling.iteration.runassess+11 moreiteration.runexecute
Static calls · unresolved targets: 0 · external targets: 6.

Source: src/profiling/iteration/root.zig:5

zig
pub const run = @import("run.zig");

Source: src/profiling/iteration/run.zig

zig
const std = @import("std");const sys = @import("sys");const profiling = @import("../root.zig");const batch = @import("batch.zig");const model = @import("model.zig");const parse = @import("parse.zig");const receipt = @import("receipt.zig");const environment = profiling.environment;const process = profiling.execute;const fingerprint = profiling.fingerprint;const host = profiling.host;const record = profiling.record;const poll_ms: u64 = 25;const timing_runner_option = "-Dtiming-runner=true";pub const Options = struct {    plan_path: []const u8,    output_dir: []const u8 = record.default_output_dir,    run_id: ?[]const u8 = null,};pub const Outcome = struct {    run_id: []const u8,    artifact_root: []const u8,    receipt_path: []const u8,    supported: bool,    reason: []const u8,};const Paths = struct {    root: []const u8,    receipt: []const u8,    backup: []const u8,    watcher_receipts: []const u8,    clean_receipts: []const u8,    clean_cache: []const u8,    watcher_stdout: []const u8,    watcher_stderr: []const u8,    clean_stdout: []const u8,    clean_stderr: []const u8,};const Source = struct {    path: []const u8,    original: []const u8,    edited: []const u8,    permissions: sys.fs.FilePermissions,    before: fingerprint.File,};const PhaseClock = struct {    started_unix_ns: i128,    started_monotonic_ns: i128,    host_state_before: host.state.Snapshot,    fn start() PhaseClock {        return .{            .started_unix_ns = sys.time.realNanoTimestamp(),            .started_monotonic_ns = sys.time.nanoTimestamp(),            .host_state_before = host.state.capture(),        };    }};pub fn execute(    allocator: std.mem.Allocator,    process_io: std.Io,    environ_map: ?*const sys.process.Environ.Map,    options: Options,) !Outcome {    const started_unix_ns = sys.time.realNanoTimestamp();    const plan_path = try sys.fs.realPathAlloc(allocator, options.plan_path);    const plan_before = try fingerprint.inspect(plan_path);    const plan = try parse.load(allocator, plan_path);    const plan_after = try fingerprint.inspect(plan_path);    if (!sameFile(plan_before, plan_after)) return error.InputChanged;    const run_id = options.run_id orelse        try record.prefixedRunId(allocator, process_io, "iteration");    try validateRunId(run_id);    const paths = try preparePaths(        allocator,        options.output_dir,        run_id,    );    const repository_root = try sys.fs.realPathAlloc(allocator, ".");    const source = try prepareSource(        allocator,        repository_root,        plan,    );    try sys.fs.writeFile(paths.backup, source.original);    const host_state_start = host.state.capture();    const host_environment = try environment.collect(        allocator,        process_io,    );    const watcher_token = try std.fmt.allocPrint(        allocator,        "{s}-watch",        .{run_id},    );    const clean_token = try std.fmt.allocPrint(        allocator,        "{s}-clean",        .{run_id},    );    const watcher_argv = try watcherArguments(        allocator,        repository_root,        plan,        paths.watcher_receipts,        watcher_token,    );    const clean_argv = try cleanArguments(        allocator,        repository_root,        plan,        paths.clean_receipts,        clean_token,    );    const baseline_clock = PhaseClock.start();    var watcher = try spawnLogged(        process_io,        environ_map,        repository_root,        watcher_argv,        paths.watcher_stdout,        paths.watcher_stderr,    );    var watcher_open = true;    defer if (watcher_open) {        _ = process.stopGroup(            &watcher,            process_io,            process.default_termination_grace_ms,        ) catch {};    };    const baseline = try waitWatcherPhase(        allocator,        &watcher,        paths.watcher_receipts,        watcher_token,        0,        null,        plan.timeout_ms,        "baseline",        baseline_clock,    );    const edit_clock = PhaseClock.start();    const edited_file = try replaceExact(        allocator,        source,        source.original,        source.edited,        run_id,    );    var source_edited = true;    errdefer if (source_edited) {        _ = replaceExact(            allocator,            source,            source.edited,            source.original,            run_id,        ) catch {};    };    const edit = try waitWatcherPhase(        allocator,        &watcher,        paths.watcher_receipts,        watcher_token,        1,        baseline.evidence.marker.finished_unix_ns,        plan.timeout_ms,        "edit",        edit_clock,    );    const clean_clock = PhaseClock.start();    const clean = try runCleanPhase(        allocator,        process_io,        environ_map,        repository_root,        clean_argv,        paths,        clean_token,        plan.timeout_ms,        clean_clock,    );    const revert_clock = PhaseClock.start();    const reverted_file = try replaceExact(        allocator,        source,        source.edited,        source.original,        run_id,    );    source_edited = false;    const revert = try waitWatcherPhase(        allocator,        &watcher,        paths.watcher_receipts,        watcher_token,        2,        edit.evidence.marker.finished_unix_ns,        plan.timeout_ms,        "revert",        revert_clock,    );    _ = try process.stopGroup(        &watcher,        process_io,        process.default_termination_grace_ms,    );    watcher_open = false;    const assessment = assess(        baseline.evidence,        edit.evidence,        clean.evidence,        revert.evidence,    );    try receipt.writeFile(        allocator,        paths.receipt,        .{            .run_id = run_id,            .artifact_root = paths.root,            .plan_path = plan_path,            .plan_file = plan_after,            .plan = plan,            .repository_root = repository_root,            .started_unix_ns = started_unix_ns,            .finished_unix_ns = sys.time.realNanoTimestamp(),            .host_environment = host_environment,            .host_state_start = host_state_start,            .source = .{                .path = source.path,                .backup_path = paths.backup,                .before = source.before,                .edited = edited_file,                .reverted = reverted_file,            },            .watcher_argv = watcher_argv,            .clean_argv = clean_argv,            .artifacts = .{                .watcher_stdout = paths.watcher_stdout,                .watcher_stderr = paths.watcher_stderr,                .clean_stdout = paths.clean_stdout,                .clean_stderr = paths.clean_stderr,                .watcher_receipts = paths.watcher_receipts,                .clean_receipts = paths.clean_receipts,                .clean_cache = paths.clean_cache,            },            .baseline = baseline,            .edit = edit,            .clean = clean,            .revert = revert,            .assessment = assessment,        },    );    return .{        .run_id = run_id,        .artifact_root = paths.root,        .receipt_path = paths.receipt,        .supported = assessment.supported,        .reason = assessment.reason,    };}fn preparePaths(    allocator: std.mem.Allocator,    output_dir: []const u8,    run_id: []const u8,) !Paths {    const requested_root = try std.fs.path.join(        allocator,        &.{ output_dir, run_id },    );    if (sys.fs.exists(requested_root)) {        return error.IterationRunExists;    }    try sys.fs.createDirPath(requested_root);    const root = try sys.fs.realPathAlloc(allocator, requested_root);    const paths = Paths{        .root = root,        .receipt = try join(allocator, root, "receipt.json"),        .backup = try join(allocator, root, "source-before"),        .watcher_receipts = try join(            allocator,            root,            "watch-receipts",        ),        .clean_receipts = try join(            allocator,            root,            "clean-receipts",        ),        .clean_cache = try join(allocator, root, "clean-cache"),        .watcher_stdout = try join(            allocator,            root,            "watcher.stdout",        ),        .watcher_stderr = try join(            allocator,            root,            "watcher.stderr",        ),        .clean_stdout = try join(            allocator,            root,            "clean.stdout",        ),        .clean_stderr = try join(            allocator,            root,            "clean.stderr",        ),    };    try sys.fs.createDirPath(paths.watcher_receipts);    try sys.fs.createDirPath(paths.clean_receipts);    try sys.fs.createDirPath(paths.clean_cache);    return paths;}fn prepareSource(    allocator: std.mem.Allocator,    repository_root: []const u8,    plan: model.Plan,) !Source {    const requested = try std.fs.path.resolve(        allocator,        &.{ repository_root, plan.patch.path },    );    const path = try sys.fs.realPathAlloc(allocator, requested);    if (!pathWithin(repository_root, path) or        std.mem.eql(u8, repository_root, path))    {        return error.IterationPatchOutsideRepository;    }    const original = try sys.fs.readFileAlloc(        allocator,        path,        model.maximum_source_bytes,    );    const first = std.mem.indexOf(        u8,        original,        plan.patch.before,    ) orelse return error.IterationPatchNotFound;    if (std.mem.indexOf(        u8,        original[first + 1 ..],        plan.patch.before,    ) != null) {        return error.IterationPatchRepeated;    }    const edited_length = std.math.add(        usize,        original.len - plan.patch.before.len,        plan.patch.after.len,    ) catch return error.IterationSourceTooLarge;    if (edited_length > model.maximum_source_bytes) {        return error.IterationSourceTooLarge;    }    const edited = try allocator.alloc(u8, edited_length);    @memcpy(edited[0..first], original[0..first]);    @memcpy(        edited[first..][0..plan.patch.after.len],        plan.patch.after,    );    const suffix = original[first + plan.patch.before.len ..];    @memcpy(        edited[first + plan.patch.after.len ..],        suffix,    );    const stat = try sys.fs.statFile(path);    const before = try fingerprint.inspect(path);    if (before.bytes != original.len or        !std.mem.eql(u8, &before.sha256, &digest(original)))    {        return error.InputChanged;    }    return .{        .path = path,        .original = original,        .edited = edited,        .permissions = stat.permissions,        .before = before,    };}fn replaceExact(    allocator: std.mem.Allocator,    source: Source,    expected: []const u8,    replacement: []const u8,    run_id: []const u8,) !fingerprint.File {    const current = try sys.fs.readFileAlloc(        allocator,        source.path,        model.maximum_source_bytes,    );    if (!std.mem.eql(u8, current, expected)) {        return error.IterationSourceChanged;    }    const pending = try std.fmt.allocPrint(        allocator,        "{s}.tiny-iteration-{s}.pending",        .{ source.path, run_id },    );    defer sys.fs.deleteFile(pending) catch {};    var file = try sys.fs.createFile(pending, .{ .truncate = true });    var open = true;    defer if (open) file.close(sys.fs.debugIo());    try sys.fs.writeHandleAll(file, replacement);    file.close(sys.fs.debugIo());    open = false;    try sys.fs.setFilePermissions(        pending,        source.permissions,        .{},    );    try sys.fs.rename(pending, source.path);    const result = try fingerprint.inspect(source.path);    const expected_digest = digest(replacement);    if (result.bytes != replacement.len or        !std.mem.eql(u8, &result.sha256, &expected_digest))    {        return error.IterationSourceWriteMismatch;    }    return result;}fn watcherArguments(    allocator: std.mem.Allocator,    repository_root: []const u8,    plan: model.Plan,    receipt_directory: []const u8,    token: []const u8,) ![]const []const u8 {    const iterate = try std.fs.path.join(        allocator,        &.{ repository_root, "skills/worktree/iterate" },    );    var arguments: std.ArrayList([]const u8) = .empty;    try arguments.appendSlice(        allocator,        &.{ iterate, "iteration-observe" },    );    try arguments.appendSlice(allocator, plan.args);    try appendGeneratedOptions(        allocator,        &arguments,        plan.step,        receipt_directory,        token,    );    return try arguments.toOwnedSlice(allocator);}fn cleanArguments(    allocator: std.mem.Allocator,    repository_root: []const u8,    plan: model.Plan,    receipt_directory: []const u8,    token: []const u8,) ![]const []const u8 {    const zig = try std.fs.path.join(        allocator,        &.{ repository_root, "skills/worktree/bin/zig" },    );    var arguments: std.ArrayList([]const u8) = .empty;    try arguments.appendSlice(        allocator,        &.{            zig,            "build",            "-fno-incremental",            "iteration-observe",        },    );    try arguments.appendSlice(allocator, plan.args);    try appendGeneratedOptions(        allocator,        &arguments,        plan.step,        receipt_directory,        token,    );    return try arguments.toOwnedSlice(allocator);}fn appendGeneratedOptions(    allocator: std.mem.Allocator,    arguments: *std.ArrayList([]const u8),    step: []const u8,    receipt_directory: []const u8,    token: []const u8,) !void {    try arguments.append(allocator, timing_runner_option);    try arguments.append(        allocator,        try option(allocator, "iteration-step", step),    );    try arguments.append(        allocator,        try option(            allocator,            "iteration-receipt-dir",            receipt_directory,        ),    );    try arguments.append(        allocator,        try option(allocator, "iteration-receipt-token", token),    );    try arguments.append(        allocator,        try option(            allocator,            "timing-receipt-dir",            receipt_directory,        ),    );    try arguments.append(        allocator,        try option(allocator, "timing-receipt-token", token),    );}fn option(    allocator: std.mem.Allocator,    name: []const u8,    value: []const u8,) ![]const u8 {    return try std.fmt.allocPrint(        allocator,        "-D{s}={s}",        .{ name, value },    );}fn spawnLogged(    process_io: std.Io,    environ_map: ?*const sys.process.Environ.Map,    cwd: []const u8,    argv: []const []const u8,    stdout_path: []const u8,    stderr_path: []const u8,) !process.Group {    const stdout_file = try sys.fs.createFile(        stdout_path,        .{ .truncate = true },    );    defer sys.fs.closeHandle(stdout_file);    const stderr_file = try sys.fs.createFile(        stderr_path,        .{ .truncate = true },    );    defer sys.fs.closeHandle(stderr_file);    return try process.spawnGroup(process_io, .{        .argv = argv,        .cwd = .{ .path = cwd },        .environ_map = environ_map,        .stdin = .ignore,        .stdout = .{ .file = stdout_file },        .stderr = .{ .file = stderr_file },    });}fn waitWatcherPhase(    allocator: std.mem.Allocator,    watcher: *process.Group,    directory: []const u8,    token: []const u8,    marker_index: usize,    previous_marker_unix_ns: ?i128,    timeout_ms: u64,    name: []const u8,    clock: PhaseClock,) !receipt.Phase {    const deadline = process.deadlineNanoseconds(        clock.started_monotonic_ns,        timeout_ms,    );    while (true) {        var scratch_state = std.heap.ArenaAllocator.init(allocator);        defer scratch_state.deinit();        if (try batch.markerAt(            scratch_state.allocator(),            directory,            token,            marker_index,        )) |temporary_marker| {            const marker = batch.Marker{                .path = try allocator.dupe(                    u8,                    temporary_marker.path,                ),                .finished_unix_ns = temporary_marker.finished_unix_ns,            };            return finishPhase(                allocator,                directory,                token,                previous_marker_unix_ns,                marker,                name,                clock,            );        }        if (!watcher.active()) return error.IterationWatcherExited;        if (try process.pollGroup(watcher)) |_| {            return error.IterationWatcherExited;        }        if (sys.time.nanoTimestamp() >= deadline) {            return error.IterationWatcherTimeout;        }        sys.time.sleepMilliseconds(poll_ms);    }}fn runCleanPhase(    allocator: std.mem.Allocator,    process_io: std.Io,    environ_map: ?*const sys.process.Environ.Map,    repository_root: []const u8,    argv: []const []const u8,    paths: Paths,    token: []const u8,    timeout_ms: u64,    clock: PhaseClock,) !receipt.Phase {    var environment_map = if (environ_map) |base|        try base.clone(allocator)    else        sys.process.Environ.Map.init(allocator);    defer environment_map.deinit();    try environment_map.put(        "ZIG_LOCAL_CACHE_DIR",        paths.clean_cache,    );    var child = try spawnLogged(        process_io,        &environment_map,        repository_root,        argv,        paths.clean_stdout,        paths.clean_stderr,    );    errdefer {        _ = process.stopGroup(            &child,            process_io,            process.default_termination_grace_ms,        ) catch {};    }    const execution = try process.awaitGroupUntil(        &child,        process_io,        process.deadlineNanoseconds(            clock.started_monotonic_ns,            timeout_ms,        ),        process.default_termination_grace_ms,    );    if (execution.status == .timed_out) {        return error.IterationCommandTimeout;    }    const term = execution.term orelse        return error.MissingIterationCommandTermination;    if (sys.process.exitCode(term) != 0) {        return error.IterationCleanBuildFailed;    }    var scratch_state = std.heap.ArenaAllocator.init(allocator);    defer scratch_state.deinit();    const temporary_marker = (try batch.markerAt(        scratch_state.allocator(),        paths.clean_receipts,        token,        0,    )) orelse return error.MissingIterationCleanMarker;    const marker = batch.Marker{        .path = try allocator.dupe(u8, temporary_marker.path),        .finished_unix_ns = temporary_marker.finished_unix_ns,    };    return finishPhase(        allocator,        paths.clean_receipts,        token,        null,        marker,        "clean",        clock,    );}fn finishPhase(    allocator: std.mem.Allocator,    directory: []const u8,    token: []const u8,    previous_marker_unix_ns: ?i128,    marker: batch.Marker,    name: []const u8,    clock: PhaseClock,) !receipt.Phase {    const finished_unix_ns = sys.time.realNanoTimestamp();    const finished_monotonic_ns = sys.time.nanoTimestamp();    return .{        .name = name,        .external_started_unix_ns = clock.started_unix_ns,        .external_finished_unix_ns = finished_unix_ns,        .external_elapsed_ns_observed = @max(            finished_monotonic_ns -                clock.started_monotonic_ns,            0,        ),        .host_state_before = clock.host_state_before,        .host_state_after = host.state.capture(),        .evidence = try batch.load(            allocator,            directory,            token,            previous_marker_unix_ns,            marker,        ),    };}fn assess(    baseline: batch.Batch,    edit: batch.Batch,    clean: batch.Batch,    revert: batch.Batch,) receipt.Assessment {    const edit_clean = equivalence(edit, clean);    const baseline_revert = equivalence(baseline, revert);    const receipts_present =        baseline.aggregate.receipt_count > 0 and        edit.aggregate.receipt_count > 0 and        clean.aggregate.receipt_count > 0 and        revert.aggregate.receipt_count > 0;    const tests_executed =        baseline.aggregate.executed_test_count > 0 and        edit.aggregate.executed_test_count > 0 and        clean.aggregate.executed_test_count > 0 and        revert.aggregate.executed_test_count > 0;    const supported = receipts_present and        tests_executed and        edit_clean.supported() and        baseline_revert.supported();    const reason = if (!receipts_present)        "no_machine_test_receipts"    else if (!tests_executed)        "no_tests_executed"    else if (!edit_clean.count_equal)        "edit_clean_test_counts_differ"    else if (!edit_clean.semantic_equal)        "edit_clean_semantic_output_differs"    else if (!edit_clean.zig_version_equal)        "edit_clean_zig_versions_differ"    else if (!baseline_revert.count_equal)        "baseline_revert_test_counts_differ"    else if (!baseline_revert.semantic_equal)        "baseline_revert_semantic_output_differs"    else if (!baseline_revert.zig_version_equal)        "baseline_revert_zig_versions_differ"    else        "clean_equivalence_and_revert_reproducibility_supported";    return .{        .supported = supported,        .reason = reason,        .edit_clean = edit_clean,        .baseline_revert = baseline_revert,    };}fn equivalence(    left: batch.Batch,    right: batch.Batch,) receipt.Equivalence {    return .{        .count_equal = countsEqual(            left.aggregate,            right.aggregate,        ),        .semantic_equal = std.mem.eql(            u8,            &left.aggregate.semantic_sha256,            &right.aggregate.semantic_sha256,        ),        .zig_version_equal = zigVersionsEqual(left, right),    };}fn countsEqual(    left: batch.Aggregate,    right: batch.Aggregate,) bool {    return left.receipt_count == right.receipt_count and        left.selected_test_count == right.selected_test_count and        left.executed_test_count == right.executed_test_count and        left.passed_test_count == right.passed_test_count and        left.skipped_test_count == right.skipped_test_count and        left.failed_test_count == right.failed_test_count;}fn zigVersionsEqual(    left: batch.Batch,    right: batch.Batch,) bool {    if (left.receipts.len == 0 or right.receipts.len == 0) {        return false;    }    const expected = left.receipts[0].zig_version;    for (left.receipts) |item| {        if (!std.mem.eql(u8, item.zig_version, expected)) return false;    }    for (right.receipts) |item| {        if (!std.mem.eql(u8, item.zig_version, expected)) return false;    }    return true;}fn digest(bytes: []const u8) fingerprint.Digest {    var result: fingerprint.Digest = undefined;    std.crypto.hash.sha2.Sha256.hash(bytes, &result, .{});    return result;}fn sameFile(    left: fingerprint.File,    right: fingerprint.File,) bool {    return left.bytes == right.bytes and        std.mem.eql(u8, &left.sha256, &right.sha256);}fn pathWithin(root: []const u8, path: []const u8) bool {    if (!std.mem.startsWith(u8, path, root) or        path.len <= root.len)    {        return false;    }    return std.fs.path.isSep(path[root.len]);}fn join(    allocator: std.mem.Allocator,    root: []const u8,    name: []const u8,) ![]const u8 {    return try std.fs.path.join(allocator, &.{ root, name });}fn validateRunId(run_id: []const u8) !void {    if (run_id.len == 0 or run_id.len > 100 or        std.mem.eql(u8, run_id, ".") or        std.mem.eql(u8, run_id, ".."))    {        return error.InvalidIterationRunId;    }    for (run_id) |byte| {        if (!std.ascii.isAlphanumeric(byte) and            byte != '.' and byte != '_' and byte != '-')        {            return error.InvalidIterationRunId;        }    }}test "iteration equivalence gates deterministic facts only" {    const digest_value = digest("same");    const item = batch.TestReceipt{        .path = "receipt",        .zig_version = "zig",        .started_unix_ns = 1,        .finished_unix_ns = 2,        .shard_count = 1,        .shard_index = 0,        .selected_test_count = 1,        .executed_test_count = 1,        .passed_test_count = 1,        .skipped_test_count = 0,        .failed_test_count = 0,        .test_ns_observed = 10,        .teardown_ns_observed = 1,        .semantic_sha256 = digest_value,    };    const evidence = batch.Batch{        .marker = .{            .path = "marker",            .finished_unix_ns = 3,        },        .receipts = &.{item},        .aggregate = .{            .receipt_count = 1,            .selected_test_count = 1,            .executed_test_count = 1,            .passed_test_count = 1,            .skipped_test_count = 0,            .failed_test_count = 0,            .test_ns_observed = 10,            .teardown_ns_observed = 1,            .semantic_sha256 = digest_value,        },    };    const result = assess(evidence, evidence, evidence, evidence);    try std.testing.expect(result.supported);}

Complete call list for iteration.run.execute

16 direct calls.

Audit

Definitions4
Public names4
Members8
Version26.7.0
Revisiondaab053ee433