Skip to documentation
SLOP

tiny.profiling.cycle

Reference tiny.profiling cycle

Defined in tiny.profiling.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

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

Source

Called byCallsNo direct callsoptionsparseCycleArgscycledefaultBaselineName
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linksrc.profiling.commandrunCycletest; no linksrc.profiling.cycletest: profiling cycle rejects timing-...baselinesaveprivate; no linksrc.profiling.cyclepruneRunsprivate; no linksrc.profiling.cycleresolvePreviousprivate; no linksrc.profiling.cyclewriteAnalysisArtifactsrecordprefixedRunIdcyclerun
Static calls · unresolved targets: 1 · external targets: 7.

Source: src/profiling/cycle.zig

zig
const std = @import("std");const pretty_usage = @import("pretty_usage");const sys = @import("sys");const analyze = @import("analyze/root.zig");const baseline = @import("baseline.zig");const catalog = @import("catalog.zig");const driver = @import("driver/root.zig");const execute = @import("execute.zig");const host = @import("host/root.zig");const perturbation = @import("perturbation.zig");const record = @import("record.zig");pub const run_id_prefix = "cycle";pub const default_step_baseline = "cycle";pub const default_binary_baseline = "cycle-binary";pub const default_mixed_baseline = "cycle-mixed";pub const Options = struct {    suite: catalog.Suite = .smoke,    filters: []const []const u8 = &.{},    output_dir: []const u8 = record.default_output_dir,    baseline_name: []const u8 = default_binary_baseline,    keep: usize = 7,    threshold_percent: f64 = 10,    top: usize = 10,    stop_on_failure: bool = false,    host_lanes: host.Options = .{},    execution_scope: execute.Scope = .binary,    warmup_repeat: u32 = 0,    measure_repeat: u32 = 1,    interleave_seed: ?u64 = null,    capture_control: perturbation.Options = .{},    forwarded: []const []const u8 = &.{},};pub fn defaultBaselineName(scope: execute.Scope) []const u8 {    return switch (scope) {        .step => default_step_baseline,        .binary => default_binary_baseline,        .mixed => default_mixed_baseline,    };}pub fn run(    memory: driver.Memory,    process_io: std.Io,    environ_map: ?*const sys.process.Environ.Map,    options: Options,) !u8 {    const allocator = memory.command;    if (options.host_lanes.requiresDirect()) return error.DirectLaneInCycle;    const stderr_terminal = pretty_usage.Terminal.stderr(allocator, .{});    const previous = resolvePrevious(allocator, options.baseline_name);    if (previous == null) {        try stderr_terminal.writeTextFmt("profile cycle: no baseline named {s}; this cycle records the first one\n", .{options.baseline_name});    }    const run_id = try record.prefixedRunId(allocator, process_io, run_id_prefix);    const outcome = try driver.executeRun(memory, process_io, environ_map, .{        .selection = .{ .suite = options.suite, .filters = options.filters },        .run_id = run_id,        .output_dir = options.output_dir,        .forwarded = options.forwarded,        .continue_on_failure = !options.stop_on_failure,        .host_lanes = options.host_lanes,        .execution_scope = options.execution_scope,        .warmup_repeat = options.warmup_repeat,        .measure_repeat = options.measure_repeat,        .interleave_seed = options.interleave_seed,        .capture_control = options.capture_control,    });    const candidate = try analyze.loadRun(allocator, outcome.paths.root);    const baseline_run: ?analyze.Run = if (previous) |ref|        analyze.loadRun(allocator, ref.root) catch |err| blk: {            try stderr_terminal.writeTextFmt("profile cycle: baseline {s} unreadable ({s}); analyzing without a baseline\n", .{ ref.run_id, @errorName(err) });            break :blk null;        }    else        null;    const analyze_options = analyze.Options{        .input = outcome.paths.root,        .top = options.top,        .regression_threshold_percent = options.threshold_percent,    };    try writeAnalysisArtifacts(allocator, outcome.paths.root, candidate, baseline_run, analyze_options);    try analyze.writeText(allocator, pretty_usage.Terminal.stdout(allocator, .{}), candidate, baseline_run, analyze_options);    const entry = try baseline.save(allocator, options.baseline_name, outcome.paths.root);    try stderr_terminal.writeTextFmt("profile cycle: baseline {s} -> {s}\n", .{ entry.name, entry.run.run_id });    const pruned = try pruneRuns(allocator, options.output_dir, options.keep);    for (pruned) |name| {        try stderr_terminal.writeTextFmt("profile cycle: pruned run {s}\n", .{name});    }    return outcome.exit_code;}fn resolvePrevious(allocator: std.mem.Allocator, baseline_name: []const u8) ?baseline.RunRef {    return baseline.resolveRun(allocator, baseline_name) catch null;}fn writeAnalysisArtifacts(    allocator: std.mem.Allocator,    run_root: []const u8,    candidate: analyze.Run,    baseline_run: ?analyze.Run,    options: analyze.Options,) !void {    const json_path = try std.fs.path.join(allocator, &.{ run_root, "analysis.json" });    var json_file = try sys.fs.createFile(json_path, .{ .truncate = true });    defer json_file.close(sys.fs.debugIo());    var json_buffer: [64 * 1024]u8 = undefined;    var json_writer = json_file.writer(sys.fs.debugIo(), &json_buffer);    try analyze.writeJson(allocator, &json_writer.interface, candidate, baseline_run, options);    try json_writer.interface.flush();    const text_path = try std.fs.path.join(allocator, &.{ run_root, "analysis.md" });    const text_file = try sys.fs.createFile(text_path, .{ .truncate = true });    defer sys.fs.closeHandle(text_file);    try analyze.writeText(allocator, pretty_usage.Terminal.init(allocator, text_file, .{}), candidate, baseline_run, options);}fn pruneRuns(allocator: std.mem.Allocator, output_dir: []const u8, keep: usize) ![]const []const u8 {    const entries = sys.fs.listDirAlloc(allocator, output_dir) catch |err| switch (err) {        error.FileNotFound => return &.{},        else => |actual| return actual,    };    var names: std.ArrayList([]const u8) = .empty;    for (entries) |entry| {        if (entry.kind != .directory) continue;        if (!isCycleRun(entry.name)) continue;        try names.append(allocator, try allocator.dupe(u8, entry.name));    }    const doomed = try pruneSelection(allocator, names.items, keep);    for (doomed) |name| {        const path = try std.fs.path.join(allocator, &.{ output_dir, name });        try sys.fs.deleteTree(path);    }    return doomed;}fn run_name_descending(_: void, left: []const u8, right: []const u8) bool {    return std.mem.order(u8, left, right) == .gt;}fn pruneSelection(allocator: std.mem.Allocator, names: []const []const u8, keep: usize) ![]const []const u8 {    const kept_count = @max(keep, 1);    if (names.len <= kept_count) return &.{};    const sorted = try allocator.dupe([]const u8, names);    std.mem.sort([]const u8, sorted, {}, run_name_descending);    return sorted[kept_count..];}fn isCycleRun(name: []const u8) bool {    if (!std.mem.startsWith(u8, name, run_id_prefix)) return false;    if (name.len == run_id_prefix.len) return false;    return name[run_id_prefix.len] == '-';}test "profiling cycle prune keeps the newest runs" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const names = [_][]const u8{        "cycle-1700000000003-ccc",        "cycle-1700000000001-aaa",        "cycle-1700000000002-bbb",    };    const doomed = try pruneSelection(allocator, &names, 2);    try std.testing.expectEqual(@as(usize, 1), doomed.len);    try std.testing.expectEqualStrings("cycle-1700000000001-aaa", doomed[0]);}test "profiling cycle prune never deletes the last kept run" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const names = [_][]const u8{"cycle-1700000000001-aaa"};    try std.testing.expectEqual(@as(usize, 0), (try pruneSelection(allocator, &names, 0)).len);    try std.testing.expectEqual(@as(usize, 0), (try pruneSelection(allocator, &names, 7)).len);}test "profiling cycle only prunes cycle-prefixed run directories" {    try std.testing.expect(isCycleRun("cycle-1700000000001-aaa"));    try std.testing.expect(!isCycleRun("cycle"));    try std.testing.expect(!isCycleRun("cyclex-1700000000001"));    try std.testing.expect(!isCycleRun("run-1700000000001-aaa"));    try std.testing.expect(!isCycleRun("baselines"));}test "profiling cycle rejects timing-perturbing direct lanes" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const memory = driver.Memory{ .command = allocator, .workload = allocator };    try std.testing.expectError(        error.DirectLaneInCycle,        run(memory, std.Options.debug_io, null, .{ .host_lanes = .{ .dhat = .{} } }),    );    try std.testing.expectError(        error.DirectLaneInCycle,        run(memory, std.Options.debug_io, null, .{ .host_lanes = .{ .offcpu = .{} } }),    );}

Source: src/profiling/root.zig:20

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

Audit

Definitions8
Public names8
Members15
Version26.7.0
Revisiondaab053ee433