Skip to documentation
SLOP

tiny.profiling.experiment.variant

Reference tiny.profiling experiment variant

Defined in experiment.

API (6)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsNo direct callsexperiment.runexecuteprivate; no linksrc.profiling.experiment.variantprepareRefexperiment.variantcleanup
Static calls · unresolved targets: 1 · external targets: 2.
Called byCallsprivate; no linksrc.profiling.experiment.acquireprepareSidetest; no linksrc.profiling.experiment.varianttest: profiling experiment prepares i...private; no linksrc.profiling.experiment.variantcatalogCommandexperiment.variantsubstitutionsscenarioresolveCommandscenariosubstituteexperiment.variantcommand
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsexperiment.runexecutetest; no linksrc.profiling.experiment.varianttest: profiling experiment prepares i...private; no linksrc.profiling.experiment.variantprepareBinaryprivate; no linksrc.profiling.experiment.variantprepareRefprivate; no linksrc.profiling.experiment.variantvariantArtifactRootexperiment.variantprepare
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsprivate; no linksrc.profiling.experiment.acquire.RunnercaptureMeasurementprivate; no linksrc.profiling.experiment.acquireprepareSideexperiment.variantcommandexperiment.variantsubstitutions
Static calls · unresolved targets: 0 · external targets: 0.

Source: src/profiling/experiment/root.zig:8

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

Source: src/profiling/experiment/variant.zig

zig
const std = @import("std");const capture = @import("capture");const sys = @import("sys");const profiling = @import("../root.zig");const model = @import("model.zig");const catalog = profiling.catalog;const code_layout = profiling.code_layout;const execute = profiling.execute;const fingerprint = profiling.fingerprint;const scenario = profiling.scenario;const maximum_git_output_bytes: usize = 4096;pub const Prepared = struct {    side: model.Side,    source: model.Variant,    resolved_ref: ?[]const u8,    worktree: ?[]const u8,    root: []const u8,    binary_path: []const u8,    archived_binary_path: []const u8,    default_cwd: []const u8,    file: fingerprint.File,    code_layout: ?capture.code_layout.Fingerprint,    build_command: ?[]const u8,};pub const Context = struct {    allocator: std.mem.Allocator,    process_io: std.Io,    environ_map: ?*const sys.process.Environ.Map,    artifact_root: []const u8,    run_id: []const u8,    definition: scenario.Definition,};pub fn prepare(    context: Context,    side: model.Side,    source: model.Variant,) !Prepared {    const variant_root = try variantArtifactRoot(        context.allocator,        context.artifact_root,        side,    );    try sys.fs.createDirPath(variant_root);    return switch (source) {        .binary => |path| try prepareBinary(            context,            side,            source,            path,            variant_root,        ),        .git_ref => |git_ref| try prepareRef(            context,            side,            source,            git_ref,            variant_root,        ),    };}fn prepareBinary(    context: Context,    side: model.Side,    source: model.Variant,    path: []const u8,    variant_root: []const u8,) !Prepared {    const allocator = context.allocator;    const source_path = try sys.fs.realPathAlloc(allocator, path);    const root = try sys.fs.realPathAlloc(allocator, ".");    const default_cwd = try defaultCwd(        allocator,        root,        context.definition,    );    return try archivePrepared(        context,        side,        source,        null,        null,        root,        source_path,        variant_root,        default_cwd,        null,    );}fn prepareRef(    context: Context,    side: model.Side,    source: model.Variant,    git_ref: model.Ref,    variant_root: []const u8,) !Prepared {    const allocator = context.allocator;    const resolved_ref = try resolveRef(        allocator,        context.process_io,        git_ref.name,    );    const worktree = try worktreePath(        allocator,        context.run_id,        side,    );    if (sys.fs.exists(worktree)) return error.ExperimentWorktreeExists;    try addWorktree(context, worktree, resolved_ref, variant_root);    errdefer cleanup(context, .{        .side = side,        .source = source,        .resolved_ref = resolved_ref,        .worktree = worktree,        .root = worktree,        .binary_path = "",        .archived_binary_path = "",        .default_cwd = worktree,        .file = undefined,        .code_layout = null,        .build_command = null,    }) catch {};    const built = try buildRef(context, worktree, git_ref, variant_root);    const default_cwd = try defaultCwd(        allocator,        worktree,        context.definition,    );    return try archivePrepared(        context,        side,        source,        resolved_ref,        worktree,        worktree,        built.artifact_path,        variant_root,        default_cwd,        built.command,    );}const Built = struct {    artifact_path: []const u8,    command: []const u8,};fn buildRef(    context: Context,    worktree: []const u8,    git_ref: model.Ref,    variant_root: []const u8,) !Built {    const build = if (git_ref.build) |definition|        try explicitBuild(context, worktree, definition)    else        try catalogBuild(context, worktree);    const stdout_path = try std.fs.path.join(        context.allocator,        &.{ variant_root, "build.stdout.txt" },    );    const stderr_path = try std.fs.path.join(        context.allocator,        &.{ variant_root, "build.stderr.txt" },    );    const result = try execute.runCommand(        context.process_io,        context.environ_map,        build.cwd,        build.argv,        stdout_path,        stderr_path,    );    if (result.exit_code != 0) return error.ExperimentBuildFailed;    return .{        .artifact_path = build.artifact_path,        .command = try execute.commandText(            context.allocator,            build.cwd,            null,            build.argv,        ),    };}const BuildCommand = struct {    argv: []const []const u8,    cwd: []const u8,    artifact_path: []const u8,};fn explicitBuild(    context: Context,    worktree: []const u8,    build: model.Build,) !BuildCommand {    const allocator = context.allocator;    const cwd = try joinScope(allocator, worktree, build.cwd);    const values = scenario.Substitutions{        .binary = build.artifact,        .root = worktree,        .side = "build",    };    const argv = try allocator.alloc([]const u8, build.argv.len);    for (build.argv, 0..) |argument, index| {        argv[index] = try scenario.substitute(allocator, argument, values);    }    if (std.mem.eql(u8, argv[0], "zig")) {        argv[0] = execute.zig(context.environ_map).executable;    }    return .{        .argv = argv,        .cwd = cwd,        .artifact_path = try std.fs.path.join(            allocator,            &.{ cwd, build.artifact },        ),    };}fn catalogBuild(    context: Context,    worktree: []const u8,) !BuildCommand {    const workload = try catalogWorkload(context.definition);    const execution_plan = try execute.plan(        context.allocator,        execute.zig(context.environ_map),        workload,        &.{},        true,        &.{execute.optimizeBuildArg(execute.default_optimize)},    );    const setup_argv = execution_plan.setup_argv orelse        return error.CatalogWorkloadMissingBinary;    const cwd = try joinScope(        context.allocator,        worktree,        execution_plan.cwd,    );    return .{        .argv = setup_argv,        .cwd = cwd,        .artifact_path = try std.fs.path.join(            context.allocator,            &.{ cwd, execution_plan.argv[0] },        ),    };}fn addWorktree(    context: Context,    path: []const u8,    resolved_ref: []const u8,    variant_root: []const u8,) !void {    const stdout_path = try std.fs.path.join(        context.allocator,        &.{ variant_root, "worktree.stdout.txt" },    );    const stderr_path = try std.fs.path.join(        context.allocator,        &.{ variant_root, "worktree.stderr.txt" },    );    const result = try execute.runCommand(        context.process_io,        context.environ_map,        null,        &.{ "git", "worktree", "add", "--detach", path, resolved_ref },        stdout_path,        stderr_path,    );    if (result.exit_code != 0) return error.ExperimentWorktreeAddFailed;}fn archivePrepared(    context: Context,    side: model.Side,    source: model.Variant,    resolved_ref: ?[]const u8,    worktree: ?[]const u8,    root: []const u8,    binary_path: []const u8,    variant_root: []const u8,    default_cwd: []const u8,    build_command: ?[]const u8,) !Prepared {    const archived = try std.fs.path.join(        context.allocator,        &.{ variant_root, "binary" },    );    const absolute_binary = try absolutePath(context.allocator, binary_path);    const absolute_archived = try unresolvedAbsolutePath(        context.allocator,        archived,    );    try std.Io.Dir.copyFileAbsolute(        absolute_binary,        absolute_archived,        std.Options.debug_io,        .{ .replace = false },    );    const file = try fingerprint.inspect(absolute_archived);    const layout_report = code_layout.inspect(        context.allocator,        &.{absolute_archived},    ) catch null;    return .{        .side = side,        .source = source,        .resolved_ref = resolved_ref,        .worktree = worktree,        .root = root,        .binary_path = absolute_archived,        .archived_binary_path = absolute_archived,        .default_cwd = default_cwd,        .file = file,        .code_layout = if (layout_report) |report|            report.images[0].fingerprint        else            null,        .build_command = build_command,    };}pub fn command(    allocator: std.mem.Allocator,    prepared: Prepared,    definition: scenario.Definition,) !scenario.Command {    const values = substitutions(prepared);    const default_cwd = if (definition.cwd) |cwd|        try scenario.substitute(allocator, cwd, values)    else        prepared.default_cwd;    return switch (definition.input) {        .command => |argv| try scenario.resolveCommand(            allocator,            .{ .argv = argv },            default_cwd,            values,        ),        .catalog => |input| try catalogCommand(            allocator,            prepared,            input,            default_cwd,        ),    };}fn catalogCommand(    allocator: std.mem.Allocator,    prepared: Prepared,    input: scenario.CatalogInput,    cwd: []const u8,) !scenario.Command {    const workload = catalog.find(input.workload) orelse        return error.UnknownWorkload;    const bin = workload.bin orelse return error.CatalogWorkloadMissingBinary;    const argument_count = 1 + bin.args.len + input.args.len;    if (argument_count > scenario.maximum_arguments) {        return error.InvalidScenarioArguments;    }    const argv = try allocator.alloc([]const u8, argument_count);    argv[0] = prepared.binary_path;    @memcpy(argv[1 .. 1 + bin.args.len], bin.args);    @memcpy(argv[1 + bin.args.len ..], input.args);    return .{ .argv = argv, .cwd = cwd };}pub fn substitutions(prepared: Prepared) scenario.Substitutions {    return .{        .binary = prepared.binary_path,        .root = prepared.root,        .side = @tagName(prepared.side),    };}pub fn cleanup(context: Context, prepared: Prepared) !void {    const worktree = prepared.worktree orelse return;    const result = try sys.process.run(        context.allocator,        context.process_io,        .{            .argv = &.{                "git",                "worktree",                "remove",                "--force",                worktree,            },            .stdout_limit = .limited(maximum_git_output_bytes),            .stderr_limit = .limited(maximum_git_output_bytes),            .environ_map = context.environ_map,        },    );    defer context.allocator.free(result.stdout);    defer context.allocator.free(result.stderr);    if (sys.process.exitCode(result.term) != 0) {        return error.ExperimentWorktreeCleanupFailed;    }}fn resolveRef(    allocator: std.mem.Allocator,    process_io: std.Io,    ref_name: []const u8,) ![]const u8 {    const commit_ref = try std.fmt.allocPrint(        allocator,        "{s}^{{commit}}",        .{ref_name},    );    const result = try sys.process.run(allocator, process_io, .{        .argv = &.{            "git",            "rev-parse",            "--verify",            "--end-of-options",            commit_ref,        },        .stdout_limit = .limited(maximum_git_output_bytes),        .stderr_limit = .limited(maximum_git_output_bytes),    });    defer allocator.free(result.stderr);    defer allocator.free(result.stdout);    if (sys.process.exitCode(result.term) != 0) return error.InvalidVariantRef;    const value = std.mem.trim(u8, result.stdout, " \t\r\n");    if (value.len != 40 and value.len != 64) return error.InvalidVariantRef;    return try allocator.dupe(u8, value);}fn defaultCwd(    allocator: std.mem.Allocator,    root: []const u8,    definition: scenario.Definition,) ![]const u8 {    return switch (definition.input) {        .command => root,        .catalog => {            const workload = try catalogWorkload(definition);            const bin = workload.bin orelse                return error.CatalogWorkloadMissingBinary;            return try joinScope(                allocator,                root,                bin.scope(workload.package),            );        },    };}fn catalogWorkload(definition: scenario.Definition) !catalog.Workload {    return switch (definition.input) {        .catalog => |input| catalog.find(input.workload) orelse            return error.UnknownWorkload,        .command => return error.InvalidCatalogScenario,    };}fn joinScope(    allocator: std.mem.Allocator,    root: []const u8,    scope: ?[]const u8,) ![]const u8 {    const value = scope orelse return root;    if (std.fs.path.isAbsolute(value)) return value;    if (std.mem.eql(u8, value, ".")) return root;    return try std.fs.path.join(allocator, &.{ root, value });}fn variantArtifactRoot(    allocator: std.mem.Allocator,    root: []const u8,    side: model.Side,) ![]const u8 {    return try std.fs.path.join(        allocator,        &.{ root, "variants", @tagName(side) },    );}fn worktreePath(    allocator: std.mem.Allocator,    run_id: []const u8,    side: model.Side,) ![]const u8 {    return try std.fmt.allocPrint(        allocator,        "/tmp/tiny-profile-{s}-{s}",        .{ run_id, @tagName(side) },    );}fn absolutePath(    allocator: std.mem.Allocator,    path: []const u8,) ![]const u8 {    if (std.fs.path.isAbsolute(path)) return path;    return try sys.fs.realPathAlloc(allocator, path);}fn unresolvedAbsolutePath(    allocator: std.mem.Allocator,    path: []const u8,) ![]const u8 {    if (std.fs.path.isAbsolute(path)) return path;    const root = try sys.fs.realPathAlloc(allocator, ".");    return try std.fs.path.join(allocator, &.{ root, path });}test "profiling experiment prepares immutable binary variants" {    var temporary = std.testing.tmpDir(.{});    defer temporary.cleanup();    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const artifact_root = try temporary.parent_dir.realPathFileAlloc(        std.Options.debug_io,        temporary.sub_path[0..],        allocator,    );    const definition = scenario.Definition{        .name = "true",        .input = .{ .command = &.{"{binary}"} },    };    const prepared = try prepare(.{        .allocator = allocator,        .process_io = std.Options.debug_io,        .environ_map = null,        .artifact_root = artifact_root,        .run_id = "variant-test",        .definition = definition,    }, .baseline, .{ .binary = "/bin/true" });    try std.testing.expect(prepared.file.bytes > 0);    try std.testing.expect(prepared.code_layout != null);    const measured = try command(allocator, prepared, definition);    try std.testing.expectEqualStrings(        prepared.binary_path,        measured.argv[0],    );}

Audit

Definitions7
Public names7
Members17
Version26.7.0
Revisiondaab053ee433