Skip to documentation
SLOP

tiny.profiling.options

Reference tiny.profiling options

Defined in tiny.profiling.

API (14)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsNo direct callstest; no linksrc.profiling.optionstest: profiling CLI parses analyze op...optionsparseAnalyzeArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI parses baseline p...private; no linksrc.profiling.optionsparseDurationNsoptionsparseBaselinePruneArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI cycle defaults ro...test; no linksrc.profiling.optionstest: profiling CLI cycle parses samp...test; no linksrc.profiling.optionstest: profiling CLI mixed cycle uses ...test; no linksrc.profiling.optionstest: profiling CLI parses bounded ca...test; no linksrc.profiling.optionstest: profiling CLI parses bounded co...+6 morecatalog.SuiteparsecycledefaultBaselineNameexecute.Scopeparseprivate; no linksrc.profiling.options.CaptureControlArgsparseprivate; no linksrc.profiling.options.CounterArgsparse+6 moreoptionsparseCycleArgs
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI parses typed expe...private; no linksrc.profiling.optionsparseTypedPlanArgsoptionsparseExperimentArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI parses typed iter...private; no linksrc.profiling.optionsparseTypedPlanArgsoptionsparseIterationArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest; no linksrc.profiling.optionstest: profiling CLI parses memory opt...optionsparseMemoryArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI parses plan optio...catalog.SuiteparseoptionsparsePlanArgs
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI parses question r...private; no linksrc.profiling.optionsnonemptyquestion.KindparseoptionsparseQuestionArgs
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI benchmark filter ...test; no linksrc.profiling.optionstest: profiling CLI causal stretch an...test; no linksrc.profiling.optionstest: profiling CLI defaults runtime ...test; no linksrc.profiling.optionstest: profiling CLI limits Tracy capt...test; no linksrc.profiling.optionstest: profiling CLI parses bounded ca...+9 morecatalog.Suiteparseexecute.Scopeparsehost.offcpu.Modeparseprivate; no linksrc.profiling.options.CaptureControlArgsparseprivate; no linksrc.profiling.options.CounterArgsparse+7 moreoptionsparseRunArgs
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callsoptionsvalidateRunOptionsoptionsselectionFromPlan
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linksrc.profiling.optionstest: profiling CLI limits Tracy capt...test; no linksrc.profiling.optionstest: profiling CLI parses bounded ca...test; no linksrc.profiling.optionstest: profiling CLI parses determinis...test; no linksrc.profiling.optionstest: profiling CLI rejects incompati...optionsselectionFromPlanperturbationvalidateCompatibilityoptionsvalidateRunOptions
Static calls · unresolved targets: 0 · external targets: 3.

Source: src/profiling/options.zig

zig
const std = @import("std");const namespace = @import("root.zig");const analyze = namespace.analyze;const baseline = namespace.baseline;const catalog = namespace.catalog;const cycle = namespace.cycle;const driver = namespace.driver;const execute = namespace.execute;const host = namespace.host;const plan = namespace.plan;const perturbation = namespace.perturbation;const question = namespace.question;const report = namespace.report.memory;const record = namespace.record;const web = namespace.report;const Allocator = std.mem.Allocator;pub const PlanOptions = struct {    suite: catalog.Suite = .standard,    filters: []const []const u8 = &.{},    json: bool = false,};pub const RunOptions = struct {    plan: PlanOptions = .{},    dry_run: bool = false,    continue_on_failure: bool = false,    output_dir: []const u8 = record.default_output_dir,    run_id: ?[]const u8 = null,    save_baseline: ?[]const u8 = null,    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 = .{},    trace_allocations: bool = false,    tracy: bool = false,    control: execute.BenchControl = .{},    forwarded: []const []const u8 = &.{},};const ExperimentOptions = struct {    plan_path: []const u8,    output_dir: []const u8 = record.default_output_dir,    run_id: ?[]const u8 = null,    dry_run: bool = false,    json: bool = false,};const IterationOptions = ExperimentOptions;const QuestionOptions = struct {    route: question.Options,    json: bool = false,};const InterleaveArgs = struct {    seed: ?u64 = null,    fn parse(self: *InterleaveArgs, args: []const []const u8, index: *usize) !bool {        const arg = args[index.*];        if (std.mem.startsWith(u8, arg, "--interleave-seed=")) {            self.seed = try parseInterleaveSeed(arg["--interleave-seed=".len..]);            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--interleave-seed")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.seed = try parseInterleaveSeed(args[index.*]);            index.* += 1;            return true;        }        return false;    }};const CaptureControlArgs = struct {    options: perturbation.Options = .{},    fn parse(self: *CaptureControlArgs, args: []const []const u8, index: *usize) !bool {        const arg = args[index.*];        if (std.mem.startsWith(u8, arg, "--capture-control-repeat=")) {            self.options.repeat = try parseCaptureControlRepeat(                arg["--capture-control-repeat=".len..],            );            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--capture-control-repeat")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.options.repeat = try parseCaptureControlRepeat(args[index.*]);            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--capture-control-seed=")) {            self.options.seed = try parseCaptureControlSeed(                arg["--capture-control-seed=".len..],            );            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--capture-control-seed")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.options.seed = try parseCaptureControlSeed(args[index.*]);            index.* += 1;            return true;        }        return false;    }};const CounterArgs = struct {    enabled: bool = false,    energy: bool = false,    events: ?[]const u8 = null,    group_size: ?u32 = null,    repeat: ?u32 = null,    fn parse(self: *CounterArgs, args: []const []const u8, index: *usize) !bool {        const arg = args[index.*];        if (std.mem.eql(u8, arg, "--counters")) {            self.enabled = true;            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--energy")) {            self.energy = true;            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--counter-events=")) {            self.events = arg["--counter-events=".len..];            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--counter-events")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.events = args[index.*];            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--counter-group-size=")) {            self.group_size = try parseCounterGroupSize(                arg["--counter-group-size=".len..],            );            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--counter-group-size")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.group_size = try parseCounterGroupSize(args[index.*]);            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--counter-repeat=")) {            self.repeat = try parseCounterRepeat(arg["--counter-repeat=".len..]);            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--counter-repeat")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.repeat = try parseCounterRepeat(args[index.*]);            index.* += 1;            return true;        }        return false;    }    fn value(self: CounterArgs) !?host.counters.Options {        if (self.energy and self.events != null) return error.EnergyCounterEventsConflict;        if (self.energy and (self.group_size orelse 0) != 0) {            return error.EnergyCounterGroupingConflict;        }        if (!self.enabled and !self.energy and self.events == null and            self.group_size == null and self.repeat == null) return null;        return .{            .events = if (self.energy)                host.counters.energy_events            else                self.events orelse host.counters.default_events,            .group_size = self.group_size orelse 0,            .repeat = self.repeat orelse host.counters.default_repeat,            .system_wide = self.energy,        };    }};const SamplingArgs = struct {    enabled: bool = false,    frequency: ?u32 = null,    min_samples: ?u64 = null,    fn parse(self: *SamplingArgs, args: []const []const u8, index: *usize) !bool {        const arg = args[index.*];        if (std.mem.eql(u8, arg, "--sampled")) {            self.enabled = true;            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--sampled-frequency=")) {            self.frequency = try parseSamplingFrequency(                arg["--sampled-frequency=".len..],            );            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--sampled-frequency")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.frequency = try parseSamplingFrequency(args[index.*]);            index.* += 1;            return true;        }        if (std.mem.startsWith(u8, arg, "--sampled-min-samples=")) {            self.min_samples = try parseMinimumSampleCount(                arg["--sampled-min-samples=".len..],            );            index.* += 1;            return true;        }        if (std.mem.eql(u8, arg, "--sampled-min-samples")) {            index.* += 1;            if (index.* >= args.len) return error.MissingArgument;            self.min_samples = try parseMinimumSampleCount(args[index.*]);            index.* += 1;            return true;        }        return false;    }    fn value(self: SamplingArgs) ?host.sampling.Options {        if (!self.enabled and self.frequency == null and self.min_samples == null) {            return null;        }        return .{            .frequency = self.frequency orelse host.sampling.default_frequency,            .min_samples = self.min_samples orelse host.sampling.default_min_samples,        };    }};pub fn parseIterationArgs(    args: []const []const u8,) !IterationOptions {    return parseTypedPlanArgs(        args,        error.MissingIterationPlan,    );}pub fn parseQuestionArgs(    args: []const []const u8,) !QuestionOptions {    var kind: ?question.Kind = null;    var workload: ?[]const u8 = null;    var plan_path: ?[]const u8 = null;    var baseline_input: ?[]const u8 = null;    var run_id: ?[]const u8 = null;    var json_output = false;    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--json")) {            json_output = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--workload=")) {            workload = try nonempty(arg["--workload=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--workload")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            workload = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--plan=")) {            plan_path = try nonempty(arg["--plan=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--plan")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            plan_path = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--baseline=")) {            baseline_input = try nonempty(                arg["--baseline=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--baseline")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            baseline_input = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--run-id=")) {            run_id = try nonempty(arg["--run-id=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--run-id")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            run_id = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "-")) {            return error.UnknownArgument;        } else {            if (kind != null) return error.UnexpectedArgument;            kind = question.Kind.parse(arg) orelse                return error.UnknownProfilingQuestion;            index += 1;        }    }    return .{        .route = .{            .kind = kind orelse return error.MissingProfilingQuestion,            .workload = workload,            .plan = plan_path,            .baseline = baseline_input,            .run_id = run_id,        },        .json = json_output,    };}pub fn parseExperimentArgs(args: []const []const u8) !ExperimentOptions {    return parseTypedPlanArgs(        args,        error.MissingExperimentPlan,    );}fn parseTypedPlanArgs(    args: []const []const u8,    missing_plan: anyerror,) !ExperimentOptions {    var plan_path: ?[]const u8 = null;    var output_dir: []const u8 = record.default_output_dir;    var run_id: ?[]const u8 = null;    var dry_run = false;    var json = false;    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--dry-run")) {            dry_run = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--json")) {            json = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--output-dir=")) {            output_dir = try nonempty(                arg["--output-dir=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--output-dir")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            output_dir = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--run-id=")) {            run_id = try nonempty(arg["--run-id=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--run-id")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            run_id = try nonempty(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "-")) {            return error.UnknownArgument;        } else {            if (plan_path != null) return error.UnexpectedArgument;            plan_path = arg;            index += 1;        }    }    return .{        .plan_path = plan_path orelse return missing_plan,        .output_dir = output_dir,        .run_id = run_id,        .dry_run = dry_run,        .json = json,    };}fn nonempty(value: []const u8) ![]const u8 {    if (value.len == 0) return error.MissingArgument;    return value;}pub fn validateRunOptions(options: RunOptions) !void {    try options.host_lanes.validate();    try driver.validateMeasureRepeat(        options.measure_repeat,        options.host_lanes,        options.tracy,        options.control.causal,    );    try perturbation.validateCompatibility(        options.capture_control,        options.measure_repeat,        options.execution_scope,        options.host_lanes,        options.tracy,        options.trace_allocations,        options.control.causal,    );    try driver.validateInterleave(        options.interleave_seed,        selectionFromPlan(options.plan).count(),        options.measure_repeat,        options.continue_on_failure,    );    if (options.tracy and options.execution_scope != .binary) {        return error.TracyRequiresBinaryScope;    }}pub fn parseCycleArgs(allocator: Allocator, args: []const []const u8) !cycle.Options {    var filters: std.ArrayList([]const u8) = .empty;    var options = cycle.Options{};    var counter_args: CounterArgs = .{};    var sampling_args: SamplingArgs = .{};    var capture_control_args: CaptureControlArgs = .{};    var interleave_args: InterleaveArgs = .{};    var baseline_explicit = false;    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (!std.mem.eql(u8, arg, "--") and try counter_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try sampling_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try capture_control_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try interleave_args.parse(args, &index)) {            continue;        }        if (std.mem.eql(u8, arg, "--")) {            options.forwarded = args[index + 1 ..];            break;        } else if (std.mem.eql(u8, arg, "--stop-on-failure")) {            options.stop_on_failure = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--workload=")) {            try filters.append(allocator, arg["--workload=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--workload")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            try filters.append(allocator, args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--suite=")) {            options.suite = catalog.Suite.parse(arg["--suite=".len..]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.eql(u8, arg, "--suite")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.suite = catalog.Suite.parse(args[index]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--baseline=")) {            options.baseline_name = arg["--baseline=".len..];            baseline_explicit = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--baseline")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.baseline_name = args[index];            baseline_explicit = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--execution-scope=")) {            options.execution_scope = execute.Scope.parse(arg["--execution-scope=".len..]) orelse return error.UnknownExecutionScope;            index += 1;        } else if (std.mem.eql(u8, arg, "--execution-scope")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.execution_scope = execute.Scope.parse(args[index]) orelse return error.UnknownExecutionScope;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--measure-repeat=")) {            options.measure_repeat = try parseMeasureRepeat(                arg["--measure-repeat=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--measure-repeat")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.measure_repeat = try parseMeasureRepeat(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--warmup-repeat=")) {            options.warmup_repeat = try parseWarmupRepeat(                arg["--warmup-repeat=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--warmup-repeat")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.warmup_repeat = try parseWarmupRepeat(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--output-dir=")) {            options.output_dir = arg["--output-dir=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--output-dir")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.output_dir = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--keep=")) {            options.keep = try std.fmt.parseInt(usize, arg["--keep=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--keep")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.keep = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--threshold=")) {            options.threshold_percent = try std.fmt.parseFloat(f64, arg["--threshold=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--threshold")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.threshold_percent = try std.fmt.parseFloat(f64, args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--top=")) {            options.top = try std.fmt.parseInt(usize, arg["--top=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--top")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.top = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else {            return error.UnknownArgument;        }    }    options.filters = filters.items;    options.interleave_seed = interleave_args.seed;    if (!baseline_explicit) options.baseline_name = cycle.defaultBaselineName(options.execution_scope);    options.host_lanes.counters = try counter_args.value();    options.host_lanes.sampling = sampling_args.value();    options.capture_control = capture_control_args.options;    return options;}const WebOptions = struct {    site: web.Options = .{},    serve: bool = false,    port: u16 = 8787,    address: []const u8 = "127.0.0.1",    json: bool = false,};pub fn parseWebArgs(args: []const []const u8) !WebOptions {    var options = WebOptions{};    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--json")) {            options.json = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--profiling-dir=")) {            options.site.profiling_dir = arg["--profiling-dir=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--profiling-dir")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.site.profiling_dir = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--output=")) {            options.site.output_dir = arg["--output=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--output")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.site.output_dir = args[index];            index += 1;        } else if (std.mem.eql(u8, arg, "--serve")) {            options.serve = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--port=")) {            options.port = try std.fmt.parseInt(u16, arg["--port=".len..], 10);            options.serve = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--port")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.port = try std.fmt.parseInt(u16, args[index], 10);            options.serve = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--address=")) {            options.address = arg["--address=".len..];            options.serve = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--address")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.address = args[index];            options.serve = true;            index += 1;        } else {            return error.UnknownArgument;        }    }    return options;}pub fn parseAnalyzeArgs(args: []const []const u8) !analyze.Options {    if (args.len == 0) return error.MissingArgument;    var options = analyze.Options{ .input = args[0] };    var index: usize = 1;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--json")) {            options.json = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--baseline=")) {            options.baseline_input = arg["--baseline=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--baseline")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.baseline_input = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--threshold=")) {            options.regression_threshold_percent = try std.fmt.parseFloat(f64, arg["--threshold=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--threshold")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.regression_threshold_percent = try std.fmt.parseFloat(f64, args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--top=")) {            options.top = try std.fmt.parseInt(usize, arg["--top=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--top")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.top = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else {            return error.UnknownArgument;        }    }    return options;}pub fn parsePlanArgs(allocator: Allocator, args: []const []const u8) !PlanOptions {    var filters: std.ArrayList([]const u8) = .empty;    var options = PlanOptions{};    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--json")) {            options.json = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--suite=")) {            options.suite = catalog.Suite.parse(arg["--suite=".len..]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.eql(u8, arg, "--suite")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.suite = catalog.Suite.parse(args[index]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--workload=")) {            try filters.append(allocator, arg["--workload=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--workload")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            try filters.append(allocator, args[index]);            index += 1;        } else {            return error.UnknownArgument;        }    }    options.filters = filters.items;    return options;}pub fn parseRunArgs(allocator: Allocator, args: []const []const u8) !RunOptions {    var filters: std.ArrayList([]const u8) = .empty;    var options = RunOptions{};    var counter_args: CounterArgs = .{};    var sampling_args: SamplingArgs = .{};    var capture_control_args: CaptureControlArgs = .{};    var interleave_args: InterleaveArgs = .{};    var dhat_enabled = false;    var offcpu_enabled = false;    var coverage_enabled = false;    var offcpu_tool: ?[]const u8 = null;    var offcpu_mode: ?host.offcpu.Mode = null;    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (!std.mem.eql(u8, arg, "--") and try counter_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try sampling_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try capture_control_args.parse(args, &index)) {            continue;        }        if (!std.mem.eql(u8, arg, "--") and try interleave_args.parse(args, &index)) {            continue;        }        if (std.mem.eql(u8, arg, "--")) {            options.forwarded = args[index + 1 ..];            break;        } else if (std.mem.eql(u8, arg, "--json")) {            options.plan.json = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--dry-run")) {            options.dry_run = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--continue-on-failure")) {            options.continue_on_failure = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--coverage")) {            coverage_enabled = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--bench-filter=")) {            options.control.filter = arg["--bench-filter=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--bench-filter")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.control.filter = args[index];            index += 1;        } else if (std.mem.eql(u8, arg, "--causal")) {            options.control.causal = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--causal-min-time=")) {            options.control.min_time_ns = try parseCausalMinTime(                arg["--causal-min-time=".len..],            );            options.control.causal = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--causal-min-time")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.control.min_time_ns = try parseCausalMinTime(args[index]);            options.control.causal = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--causal-filter=")) {            options.control.filter = arg["--causal-filter=".len..];            options.control.causal = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--causal-filter")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.control.filter = args[index];            options.control.causal = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--dhat")) {            dhat_enabled = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--tracy")) {            options.tracy = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--trace-allocations")) {            options.trace_allocations = true;            index += 1;        } else if (std.mem.eql(u8, arg, "--offcpu")) {            offcpu_enabled = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--offcpu-tool=")) {            offcpu_tool = arg["--offcpu-tool=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--offcpu-tool")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            offcpu_tool = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--offcpu-mode=")) {            offcpu_mode = host.offcpu.Mode.parse(arg["--offcpu-mode=".len..]) orelse return error.UnknownOffcpuMode;            index += 1;        } else if (std.mem.eql(u8, arg, "--offcpu-mode")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            offcpu_mode = host.offcpu.Mode.parse(args[index]) orelse return error.UnknownOffcpuMode;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--output-dir=")) {            options.output_dir = arg["--output-dir=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--output-dir")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.output_dir = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--run-id=")) {            options.run_id = arg["--run-id=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--run-id")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.run_id = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--save-baseline=")) {            options.save_baseline = arg["--save-baseline=".len..];            index += 1;        } else if (std.mem.eql(u8, arg, "--save-baseline")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.save_baseline = args[index];            index += 1;        } else if (std.mem.startsWith(u8, arg, "--execution-scope=")) {            options.execution_scope = execute.Scope.parse(arg["--execution-scope=".len..]) orelse return error.UnknownExecutionScope;            index += 1;        } else if (std.mem.eql(u8, arg, "--execution-scope")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.execution_scope = execute.Scope.parse(args[index]) orelse return error.UnknownExecutionScope;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--measure-repeat=")) {            options.measure_repeat = try parseMeasureRepeat(                arg["--measure-repeat=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--measure-repeat")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.measure_repeat = try parseMeasureRepeat(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--warmup-repeat=")) {            options.warmup_repeat = try parseWarmupRepeat(                arg["--warmup-repeat=".len..],            );            index += 1;        } else if (std.mem.eql(u8, arg, "--warmup-repeat")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.warmup_repeat = try parseWarmupRepeat(args[index]);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--suite=")) {            options.plan.suite = catalog.Suite.parse(arg["--suite=".len..]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.eql(u8, arg, "--suite")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.plan.suite = catalog.Suite.parse(args[index]) orelse return error.UnknownSuite;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--workload=")) {            try filters.append(allocator, arg["--workload=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--workload")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            try filters.append(allocator, args[index]);            index += 1;        } else {            return error.UnknownArgument;        }    }    options.plan.filters = filters.items;    options.interleave_seed = interleave_args.seed;    options.host_lanes.counters = try counter_args.value();    options.host_lanes.sampling = sampling_args.value();    options.capture_control = capture_control_args.options;    if (dhat_enabled) {        options.host_lanes.dhat = .{};    }    if (offcpu_enabled or offcpu_tool != null or offcpu_mode != null) {        options.host_lanes.offcpu = .{ .tool = offcpu_tool, .mode = offcpu_mode orelse .time };    }    if (coverage_enabled) {        options.host_lanes.coverage = .{};    }    return options;}fn parseCausalMinTime(text: []const u8) !u64 {    const seconds = std.fmt.parseUnsigned(u64, text, 10) catch return error.InvalidCausalMinTime;    return std.math.mul(u64, seconds, std.time.ns_per_s) catch error.InvalidCausalMinTime;}fn parseCounterRepeat(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidCounterRepeat;    if (!host.process.validRepeat(value)) return error.InvalidCounterRepeat;    return value;}fn parseMeasureRepeat(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidMeasureRepeat;    if (!host.process.validRepeat(value)) {        return error.InvalidMeasureRepeat;    }    return value;}fn parseInterleaveSeed(text: []const u8) !u64 {    return std.fmt.parseUnsigned(u64, text, 10) catch        error.InvalidInterleaveSeed;}fn parseWarmupRepeat(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidWarmupRepeat;    if (!host.process.validWarmupRepeat(value)) {        return error.InvalidWarmupRepeat;    }    return value;}fn parseCaptureControlRepeat(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidCaptureControlRepeat;    if (value == 0 or value > perturbation.max_pairs) {        return error.InvalidCaptureControlRepeat;    }    return value;}fn parseCaptureControlSeed(text: []const u8) !u64 {    return std.fmt.parseUnsigned(u64, text, 10) catch        error.InvalidCaptureControlSeed;}fn parseCounterGroupSize(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidCounterGroupSize;    if (value > host.counters.max_group_size) return error.InvalidCounterGroupSize;    return value;}fn parseSamplingFrequency(text: []const u8) !u32 {    const value = std.fmt.parseUnsigned(u32, text, 10) catch        return error.InvalidSamplingFrequency;    if (value == 0) return error.InvalidSamplingFrequency;    return value;}fn parseMinimumSampleCount(text: []const u8) !u64 {    const value = std.fmt.parseUnsigned(u64, text, 10) catch        return error.InvalidMinimumSampleCount;    if (value == 0) return error.InvalidMinimumSampleCount;    return value;}pub fn parseMemoryArgs(args: []const []const u8) !report.Options {    if (args.len == 0) return error.MissingArgument;    var options = report.Options{ .input = args[0] };    var index: usize = 1;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--json")) {            options.json = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--top=")) {            options.top = try std.fmt.parseInt(usize, arg["--top=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--top")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.top = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--min-bytes=")) {            options.min_bytes = try std.fmt.parseInt(usize, arg["--min-bytes=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--min-bytes")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.min_bytes = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else {            return error.UnknownArgument;        }    }    return options;}pub fn parseBaselinePruneArgs(args: []const []const u8) !baseline.PruneOptions {    var options = baseline.PruneOptions{};    var index: usize = 0;    while (index < args.len) {        const arg = args[index];        if (std.mem.eql(u8, arg, "--dry-run")) {            options.dry_run = true;            index += 1;        } else if (std.mem.startsWith(u8, arg, "--keep-last=")) {            options.keep_last = try std.fmt.parseInt(usize, arg["--keep-last=".len..], 10);            index += 1;        } else if (std.mem.eql(u8, arg, "--keep-last")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.keep_last = try std.fmt.parseInt(usize, args[index], 10);            index += 1;        } else if (std.mem.startsWith(u8, arg, "--older-than=")) {            options.older_than_ns = try parseDurationNs(arg["--older-than=".len..]);            index += 1;        } else if (std.mem.eql(u8, arg, "--older-than")) {            index += 1;            if (index >= args.len) return error.MissingArgument;            options.older_than_ns = try parseDurationNs(args[index]);            index += 1;        } else {            return error.UnknownArgument;        }    }    if (options.keep_last == null and options.older_than_ns == null) return error.MissingPruneRule;    return options;}fn parseDurationNs(value: []const u8) !i128 {    if (value.len < 2) return error.InvalidDuration;    const suffix = value[value.len - 1];    const multiplier: i128 = switch (suffix) {        's' => std.time.ns_per_s,        'm' => std.time.ns_per_min,        'h' => std.time.ns_per_hour,        'd' => std.time.ns_per_day,        else => return error.InvalidDuration,    };    const number = try std.fmt.parseInt(i128, value[0 .. value.len - 1], 10);    if (number < 0) return error.InvalidDuration;    return number * multiplier;}pub fn selectionFromPlan(options: PlanOptions) plan.Selection {    return .{ .suite = options.suite, .filters = options.filters };}test "profiling CLI parses plan options" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parsePlanArgs(arena_state.allocator(), &.{ "--suite", "smoke", "--workload", "smg-bench", "--json" });    try std.testing.expectEqual(catalog.Suite.smoke, options.suite);    try std.testing.expect(options.json);    try std.testing.expectEqual(@as(usize, 1), options.filters.len);    try std.testing.expectEqualStrings("smg-bench", options.filters[0]);}test "profiling CLI parses run forwarded args" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseRunArgs(arena_state.allocator(), &.{ "--suite=all", "--dry-run", "--tracy", "--trace-allocations", "--execution-scope=binary", "--warmup-repeat=2", "--measure-repeat=1", "--output-dir", "zig-out/custom", "--run-id", "run-a", "--save-baseline", "main", "--", "--test-filter", "bench:" });    try std.testing.expectEqual(catalog.Suite.all, options.plan.suite);    try std.testing.expect(options.dry_run);    try std.testing.expectEqualStrings("zig-out/custom", options.output_dir);    try std.testing.expectEqualStrings("run-a", options.run_id.?);    try std.testing.expectEqualStrings("main", options.save_baseline.?);    try std.testing.expectEqual(execute.Scope.binary, options.execution_scope);    try std.testing.expectEqual(@as(u32, 2), options.warmup_repeat);    try std.testing.expectEqual(@as(u32, 1), options.measure_repeat);    try std.testing.expect(options.tracy);    try std.testing.expect(options.trace_allocations);    try std.testing.expectEqual(@as(usize, 2), options.forwarded.len);}test "profiling CLI defaults runtime runs to prepared binaries" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseRunArgs(arena_state.allocator(), &.{});    try std.testing.expectEqual(execute.Scope.binary, options.execution_scope);    try std.testing.expectEqual(        std.builtin.OptimizeMode.fast,        driver.effectiveOptimize(options.host_lanes),    );    try std.testing.expectError(        error.UnknownArgument,        parseRunArgs(arena_state.allocator(), &.{ "--optimize", "ReleaseSafe" }),    );}test "profiling CLI limits Tracy capture to prepared binaries" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const step_options = try parseRunArgs(        arena_state.allocator(),        &.{ "--tracy", "--execution-scope=step" },    );    try std.testing.expectError(error.TracyRequiresBinaryScope, validateRunOptions(step_options));    const mixed_options = try parseRunArgs(        arena_state.allocator(),        &.{ "--tracy", "--execution-scope=mixed" },    );    try std.testing.expectError(error.TracyRequiresBinaryScope, validateRunOptions(mixed_options));}test "profiling CLI validates workload filters" {    try plan.validateFilters(&.{"smg.graph"});    try std.testing.expectError(error.UnknownWorkload, plan.validateFilters(&.{"missing"}));}test "profiling CLI causal stretch and filter imply the causal lane" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseRunArgs(arena_state.allocator(), &.{ "--causal-min-time", "30", "--causal-filter=small alloc" });    try std.testing.expect(options.control.causal);    try std.testing.expectEqual(@as(?u64, 30_000_000_000), options.control.min_time_ns);    try std.testing.expectEqualStrings("small alloc", options.control.filter.?);    const bare = try parseRunArgs(arena_state.allocator(), &.{"--causal"});    try std.testing.expect(bare.control.causal);    try std.testing.expectEqual(@as(?u64, null), bare.control.min_time_ns);    try std.testing.expect(bare.control.filter == null);    try std.testing.expectError(error.InvalidCausalMinTime, parseRunArgs(arena_state.allocator(), &.{ "--causal-min-time", "30s" }));}test "profiling CLI benchmark filter preserves the ordinary lane" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const joined = try parseRunArgs(        allocator,        &.{"--bench-filter=program image cache"},    );    try std.testing.expect(!joined.control.causal);    try std.testing.expectEqualStrings(        "program image cache",        joined.control.filter.?,    );    const split = try parseRunArgs(        allocator,        &.{ "--bench-filter", "small alloc" },    );    try std.testing.expect(!split.control.causal);    try std.testing.expectEqualStrings("small alloc", split.control.filter.?);}test "profiling CLI parses sampling support controls" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const options = try parseRunArgs(        allocator,        &.{ "--sampled-frequency", "997", "--sampled-min-samples=900" },    );    const sampling = options.host_lanes.sampling.?;    try std.testing.expectEqual(@as(u32, 997), sampling.frequency);    try std.testing.expectEqual(@as(u64, 900), sampling.min_samples);    try std.testing.expectError(        error.InvalidSamplingFrequency,        parseRunArgs(allocator, &.{ "--sampled-frequency", "0" }),    );    try std.testing.expectError(        error.InvalidMinimumSampleCount,        parseRunArgs(allocator, &.{ "--sampled-min-samples", "0" }),    );    try std.testing.expectError(        error.UnknownArgument,        parseRunArgs(allocator, &.{ "--sampled-scope", "step" }),    );}test "profiling CLI parses bounded counter groups and repetitions" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const defaults = try parseRunArgs(allocator, &.{"--counters"});    try std.testing.expectEqualStrings(        host.counters.default_events,        defaults.host_lanes.counters.?.events,    );    try std.testing.expectEqual(        host.counters.default_repeat,        defaults.host_lanes.counters.?.repeat,    );    const single = try parseRunArgs(allocator, &.{"--counter-repeat=1"});    try std.testing.expectEqual(@as(u32, 1), single.host_lanes.counters.?.repeat);    const options = try parseRunArgs(        allocator,        &.{ "--counter-events", "cycles,instructions", "--counter-group-size=1", "--counter-repeat=3" },    );    const counters = options.host_lanes.counters.?;    try std.testing.expectEqualStrings("cycles,instructions", counters.events);    try std.testing.expectEqual(@as(u32, 1), counters.group_size);    try std.testing.expectEqual(@as(u32, 3), counters.repeat);    const repeated_cycle = try parseCycleArgs(allocator, &.{"--counter-repeat=4"});    try std.testing.expectEqual(        @as(u32, 4),        repeated_cycle.host_lanes.counters.?.repeat,    );    try std.testing.expectError(        error.InvalidCounterRepeat,        parseRunArgs(allocator, &.{ "--counter-repeat", "0" }),    );    try std.testing.expectError(        error.InvalidCounterRepeat,        parseCycleArgs(allocator, &.{"--counter-repeat=101"}),    );    try std.testing.expectError(        error.InvalidCounterGroupSize,        parseRunArgs(allocator, &.{"--counter-group-size=101"}),    );}test "profiling CLI selects paired system domain energy evidence" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const options = try parseRunArgs(        allocator,        &.{ "--energy", "--counter-repeat=4" },    );    const counters = options.host_lanes.counters.?;    try std.testing.expectEqualStrings(host.counters.energy_events, counters.events);    try std.testing.expectEqual(@as(u32, 4), counters.repeat);    try std.testing.expectEqual(@as(u32, 0), counters.group_size);    try std.testing.expect(counters.system_wide);    const cycle_options_value = try parseCycleArgs(allocator, &.{"--energy"});    try std.testing.expect(cycle_options_value.host_lanes.counters.?.system_wide);    try std.testing.expectError(        error.EnergyCounterEventsConflict,        parseRunArgs(allocator, &.{ "--energy", "--counter-events=cycles" }),    );    try std.testing.expectError(        error.EnergyCounterGroupingConflict,        parseRunArgs(allocator, &.{ "--energy", "--counter-group-size=1" }),    );}test "profiling CLI parses bounded ordinary process repetitions" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const options = try parseRunArgs(allocator, &.{"--measure-repeat=3"});    try std.testing.expectEqual(@as(u32, 3), options.measure_repeat);    const cycle_options_value = try parseCycleArgs(        allocator,        &.{ "--measure-repeat", "4" },    );    try std.testing.expectEqual(@as(u32, 4), cycle_options_value.measure_repeat);    try std.testing.expectError(        error.InvalidMeasureRepeat,        parseRunArgs(allocator, &.{ "--measure-repeat", "0" }),    );    try std.testing.expectError(        error.InvalidMeasureRepeat,        parseCycleArgs(allocator, &.{"--measure-repeat=101"}),    );}test "profiling CLI parses deterministic repetition interleaving" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const options = try parseRunArgs(        allocator,        &.{ "--measure-repeat=9", "--interleave-seed", "42", "--continue-on-failure" },    );    try std.testing.expectEqual(@as(?u64, 42), options.interleave_seed);    try std.testing.expect(options.continue_on_failure);    try validateRunOptions(options);    const cycle_options_value = try parseCycleArgs(        allocator,        &.{ "--measure-repeat", "7", "--interleave-seed=99" },    );    try std.testing.expectEqual(@as(?u64, 99), cycle_options_value.interleave_seed);    try std.testing.expectError(        error.InvalidInterleaveSeed,        parseRunArgs(allocator, &.{ "--interleave-seed", "random" }),    );}test "profiling CLI parses bounded unmeasured process warmups" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const zero = try parseRunArgs(allocator, &.{"--warmup-repeat=0"});    try std.testing.expectEqual(@as(u32, 0), zero.warmup_repeat);    const maximum = try parseCycleArgs(        allocator,        &.{ "--warmup-repeat", "100" },    );    try std.testing.expectEqual(@as(u32, 100), maximum.warmup_repeat);    try std.testing.expectError(        error.InvalidWarmupRepeat,        parseRunArgs(allocator, &.{ "--warmup-repeat", "101" }),    );    try std.testing.expectError(        error.InvalidWarmupRepeat,        parseCycleArgs(allocator, &.{"--warmup-repeat=invalid"}),    );}test "profiling CLI parses bounded capture control pairs" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const options = try parseRunArgs(allocator, &.{        "--sampled",        "--capture-control-repeat=5",        "--capture-control-seed",        "42",    });    try std.testing.expectEqual(@as(u32, 5), options.capture_control.repeat);    try std.testing.expectEqual(@as(u64, 42), options.capture_control.seed);    try validateRunOptions(options);    const cycle_options_value = try parseCycleArgs(allocator, &.{        "--sampled",        "--capture-control-repeat",        "4",        "--capture-control-seed=7",    });    try std.testing.expectEqual(        @as(u32, 4),        cycle_options_value.capture_control.repeat,    );    try std.testing.expectEqual(        @as(u64, 7),        cycle_options_value.capture_control.seed,    );    try std.testing.expectError(        error.InvalidCaptureControlRepeat,        parseRunArgs(allocator, &.{ "--capture-control-repeat", "0" }),    );    try std.testing.expectError(        error.InvalidCaptureControlRepeat,        parseCycleArgs(allocator, &.{"--capture-control-repeat=51"}),    );    try std.testing.expectError(        error.InvalidCaptureControlSeed,        parseRunArgs(allocator, &.{ "--capture-control-seed", "seed" }),    );}test "profiling CLI rejects incompatible capture control designs" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const allocator = arena_state.allocator();    const no_capture = try parseRunArgs(        allocator,        &.{ "--capture-control-repeat", "3" },    );    try std.testing.expectError(        error.CaptureControlRequiresCapture,        validateRunOptions(no_capture),    );    const step_scope = try parseRunArgs(allocator, &.{        "--sampled",        "--execution-scope=step",        "--capture-control-repeat=3",    });    try std.testing.expectError(        error.CaptureControlRequiresBinaryScope,        validateRunOptions(step_scope),    );    const mixed_scope = try parseRunArgs(allocator, &.{        "--sampled",        "--execution-scope=mixed",        "--capture-control-repeat=3",    });    try std.testing.expectError(        error.CaptureControlRequiresBinaryScope,        validateRunOptions(mixed_scope),    );    const repeated = try parseRunArgs(allocator, &.{        "--sampled",        "--measure-repeat=2",        "--capture-control-repeat=3",    });    try std.testing.expectError(        error.MeasureRepeatConflictsWithCapture,        validateRunOptions(repeated),    );    const causal = try parseRunArgs(allocator, &.{        "--tracy",        "--causal",        "--capture-control-repeat=3",    });    try std.testing.expectError(        error.CaptureControlConflictsWithCausal,        validateRunOptions(causal),    );    const counter_matrix = try parseRunArgs(allocator, &.{        "--counter-repeat=2",        "--capture-control-repeat=3",    });    try std.testing.expectError(        error.CaptureControlConflictsWithCounterMatrix,        validateRunOptions(counter_matrix),    );}test "profiling CLI parses source coverage lane" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseRunArgs(arena_state.allocator(), &.{"--coverage"});    try std.testing.expect(options.host_lanes.coverage != null);    try std.testing.expect(options.host_lanes.requiresDirect());    try std.testing.expectEqual(        std.builtin.OptimizeMode.debug,        driver.effectiveOptimize(options.host_lanes),    );}test "profiling CLI parses cycle options" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseCycleArgs(arena_state.allocator(), &.{ "--suite", "standard", "--workload", "mprompt.smoke", "--baseline", "weekly", "--execution-scope", "step", "--warmup-repeat", "2", "--measure-repeat", "4", "--output-dir", "zig-out/custom", "--keep=3", "--threshold", "7.5", "--top=4", "--stop-on-failure", "--", "--warmup", "0" });    try std.testing.expectEqual(catalog.Suite.standard, options.suite);    try std.testing.expectEqual(@as(usize, 1), options.filters.len);    try std.testing.expectEqualStrings("mprompt.smoke", options.filters[0]);    try std.testing.expectEqualStrings("weekly", options.baseline_name);    try std.testing.expectEqual(execute.Scope.step, options.execution_scope);    try std.testing.expectEqual(@as(u32, 2), options.warmup_repeat);    try std.testing.expectEqual(@as(u32, 4), options.measure_repeat);    try std.testing.expectEqualStrings("zig-out/custom", options.output_dir);    try std.testing.expectEqual(@as(usize, 3), options.keep);    try std.testing.expectEqual(@as(f64, 7.5), options.threshold_percent);    try std.testing.expectEqual(@as(usize, 4), options.top);    try std.testing.expect(options.stop_on_failure);    try std.testing.expectEqual(@as(usize, 2), options.forwarded.len);}test "profiling CLI cycle defaults roll the smoke suite" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseCycleArgs(arena_state.allocator(), &.{});    try std.testing.expectEqual(catalog.Suite.smoke, options.suite);    try std.testing.expectEqual(@as(usize, 0), options.filters.len);    try std.testing.expectEqual(execute.Scope.binary, options.execution_scope);    try std.testing.expectEqualStrings("cycle-binary", options.baseline_name);    try std.testing.expectEqual(@as(usize, 7), options.keep);    try std.testing.expect(!options.stop_on_failure);}test "profiling CLI cycle parses sampling support controls" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseCycleArgs(        arena_state.allocator(),        &.{ "--sampled-frequency=499", "--sampled-min-samples", "800" },    );    const sampling = options.host_lanes.sampling.?;    try std.testing.expectEqual(@as(u32, 499), sampling.frequency);    try std.testing.expectEqual(@as(u64, 800), sampling.min_samples);}test "profiling CLI step cycle defaults to the legacy baseline" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseCycleArgs(arena_state.allocator(), &.{ "--execution-scope", "step" });    try std.testing.expectEqual(execute.Scope.step, options.execution_scope);    try std.testing.expectEqualStrings("cycle", options.baseline_name);}test "profiling CLI mixed cycle uses an isolated baseline" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const options = try parseCycleArgs(arena_state.allocator(), &.{ "--execution-scope", "mixed" });    try std.testing.expectEqual(execute.Scope.mixed, options.execution_scope);    try std.testing.expectEqualStrings("cycle-mixed", options.baseline_name);}test "profiling CLI parses analyze options" {    const options = try parseAnalyzeArgs(&.{ "zig-out/profiling/run-a", "--baseline", "main", "--threshold", "7.5", "--top=3", "--json" });    try std.testing.expectEqualStrings("zig-out/profiling/run-a", options.input);    try std.testing.expectEqualStrings("main", options.baseline_input.?);    try std.testing.expectEqual(@as(usize, 3), options.top);    try std.testing.expect(options.json);}test "profiling CLI parses memory options" {    const options = try parseMemoryArgs(&.{ "zig-out/profiling/run-a", "--top", "7", "--min-bytes=32", "--json" });    try std.testing.expectEqualStrings("zig-out/profiling/run-a", options.input);    try std.testing.expectEqual(@as(usize, 7), options.top);    try std.testing.expectEqual(@as(usize, 32), options.min_bytes);    try std.testing.expect(options.json);}test "profiling CLI parses baseline prune options" {    const options = try parseBaselinePruneArgs(&.{ "--keep-last", "3", "--older-than=14d", "--dry-run" });    try std.testing.expectEqual(@as(usize, 3), options.keep_last.?);    try std.testing.expectEqual(@as(i128, 14 * std.time.ns_per_day), options.older_than_ns.?);    try std.testing.expect(options.dry_run);    try std.testing.expectError(error.MissingPruneRule, parseBaselinePruneArgs(&.{"--dry-run"}));}test "profiling CLI parses typed experiment options" {    const options = try parseExperimentArgs(&.{        "experiment.json",        "--output-dir=zig-out/evidence",        "--run-id",        "candidate-a",        "--dry-run",        "--json",    });    try std.testing.expectEqualStrings("experiment.json", options.plan_path);    try std.testing.expectEqualStrings("zig-out/evidence", options.output_dir);    try std.testing.expectEqualStrings("candidate-a", options.run_id.?);    try std.testing.expect(options.dry_run);    try std.testing.expect(options.json);    try std.testing.expectError(        error.MissingExperimentPlan,        parseExperimentArgs(&.{"--json"}),    );    try std.testing.expectError(        error.UnexpectedArgument,        parseExperimentArgs(&.{ "first.json", "second.json" }),    );}test "profiling CLI parses typed iteration options" {    const options = try parseIterationArgs(&.{        "iteration.json",        "--output-dir=zig-out/evidence",        "--run-id",        "edit-a",        "--dry-run",        "--json",    });    try std.testing.expectEqualStrings("iteration.json", options.plan_path);    try std.testing.expectEqualStrings("zig-out/evidence", options.output_dir);    try std.testing.expectEqualStrings("edit-a", options.run_id.?);    try std.testing.expect(options.dry_run);    try std.testing.expect(options.json);    try std.testing.expectError(        error.MissingIterationPlan,        parseIterationArgs(&.{"--json"}),    );}test "profiling CLI parses question routing inputs" {    const options = try parseQuestionArgs(&.{        "hotspot",        "--workload",        "gpalloc.allocator",        "--run-id=hot-a",        "--baseline",        "main",        "--json",    });    try std.testing.expectEqual(question.Kind.hotspot, options.route.kind);    try std.testing.expectEqualStrings(        "gpalloc.allocator",        options.route.workload.?,    );    try std.testing.expectEqualStrings("hot-a", options.route.run_id.?);    try std.testing.expectEqualStrings("main", options.route.baseline.?);    try std.testing.expect(options.json);    try std.testing.expectError(        error.MissingProfilingQuestion,        parseQuestionArgs(&.{"--json"}),    );}

Source: src/profiling/root.zig:18

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

Complete caller list for options.parseCycleArgs

11 direct callers.

Complete call list for options.parseCycleArgs

11 direct calls.

Complete caller list for options.parseRunArgs

14 direct callers.

Complete call list for options.parseRunArgs

12 direct calls.

Audit

Definitions15
Public names15
Members19
Version26.7.0
Revisiondaab053ee433