tiny.profiling.options
Defined in tiny.profiling.
API (14)
Actions
Public operations.
parseAnalyzeArgsparseBaselinePruneArgsparseCycleArgsparseExperimentArgsparseIterationArgsparseMemoryArgsparsePlanArgsparseQuestionArgsparseRunArgsparseWebArgsselectionFromPlanvalidateRunOptions
Types and contracts
Public types and contracts.
Source
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.
src.profiling.options.test_profiling_CLI_cycle_defaults_roll_the_smoke_suite[function] — test; no exact target atsrc/profiling/options.zig:1415in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_cycle_parses_sampling_support_controls[function] — test; no exact target atsrc/profiling/options.zig:1427in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_mixed_cycle_uses_an_isolated_baseline[function] — test; no exact target atsrc/profiling/options.zig:1447in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_capture_control_pairs[function] — test; no exact target atsrc/profiling/options.zig:1285in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_counter_groups_and_repetitions[function] — test; no exact target atsrc/profiling/options.zig:1154in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_ordinary_process_repetitions[function] — test; no exact target atsrc/profiling/options.zig:1221in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_unmeasured_process_warmups[function] — test; no exact target atsrc/profiling/options.zig:1264in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_cycle_options[function] — test; no exact target atsrc/profiling/options.zig:1396in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_deterministic_repetition_interleaving[function] — test; no exact target atsrc/profiling/options.zig:1242in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_selects_paired_system_domain_energy_evidence[function] — test; no exact target atsrc/profiling/options.zig:1196in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_step_cycle_defaults_to_the_legacy_baseline[function] — test; no exact target atsrc/profiling/options.zig:1439in nearest public ownertiny.profiling.options
Complete call list for options.parseCycleArgs
11 direct calls.
tiny.profiling.catalog.Suite.parse[function] atsrc/profiling/catalog.zig:11tiny.profiling.cycle.defaultBaselineName[function] atsrc/profiling/cycle.zig:37tiny.profiling.execute.Scope.parse[function] atsrc/profiling/execute.zig:115src.profiling.options.CaptureControlArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:83in nearest public ownertiny.profiling.optionssrc.profiling.options.CounterArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:124in nearest public ownertiny.profiling.optionssrc.profiling.options.CounterArgs.value[method] — private; no exact target atsrc/profiling/options.zig:177in nearest public ownertiny.profiling.optionssrc.profiling.options.InterleaveArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:62in nearest public ownertiny.profiling.optionssrc.profiling.options.SamplingArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:201in nearest public ownertiny.profiling.optionssrc.profiling.options.SamplingArgs.value[method] — private; no exact target atsrc/profiling/options.zig:239in nearest public ownertiny.profiling.optionssrc.profiling.options.parseMeasureRepeat[function] — private; no exact target atsrc/profiling/options.zig:889in nearest public ownertiny.profiling.optionssrc.profiling.options.parseWarmupRepeat[function] — private; no exact target atsrc/profiling/options.zig:903in nearest public ownertiny.profiling.options
Complete caller list for options.parseRunArgs
14 direct callers.
src.profiling.options.test_profiling_CLI_benchmark_filter_preserves_the_ordinary_lane[function] — test; no exact target atsrc/profiling/options.zig:1108in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_causal_stretch_and_filter_imply_the_causal_lane[function] — test; no exact target atsrc/profiling/options.zig:1092in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_defaults_runtime_runs_to_prepared_binaries[function] — test; no exact target atsrc/profiling/options.zig:1057in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_limits_Tracy_capture_to_prepared_binaries[function] — test; no exact target atsrc/profiling/options.zig:1072in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_capture_control_pairs[function] — test; no exact target atsrc/profiling/options.zig:1285in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_counter_groups_and_repetitions[function] — test; no exact target atsrc/profiling/options.zig:1154in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_ordinary_process_repetitions[function] — test; no exact target atsrc/profiling/options.zig:1221in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_bounded_unmeasured_process_warmups[function] — test; no exact target atsrc/profiling/options.zig:1264in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_deterministic_repetition_interleaving[function] — test; no exact target atsrc/profiling/options.zig:1242in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_run_forwarded_args[function] — test; no exact target atsrc/profiling/options.zig:1040in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_sampling_support_controls[function] — test; no exact target atsrc/profiling/options.zig:1129in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_parses_source_coverage_lane[function] — test; no exact target atsrc/profiling/options.zig:1384in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_rejects_incompatible_capture_control_designs[function] — test; no exact target atsrc/profiling/options.zig:1326in nearest public ownertiny.profiling.optionssrc.profiling.options.test_profiling_CLI_selects_paired_system_domain_energy_evidence[function] — test; no exact target atsrc/profiling/options.zig:1196in nearest public ownertiny.profiling.options
Complete call list for options.parseRunArgs
12 direct calls.
tiny.profiling.catalog.Suite.parse[function] atsrc/profiling/catalog.zig:11tiny.profiling.execute.Scope.parse[function] atsrc/profiling/execute.zig:115tiny.profiling.host.offcpu.Mode.parse[function] atsrc/profiling/host/offcpu.zig:15src.profiling.options.CaptureControlArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:83in nearest public ownertiny.profiling.optionssrc.profiling.options.CounterArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:124in nearest public ownertiny.profiling.optionssrc.profiling.options.CounterArgs.value[method] — private; no exact target atsrc/profiling/options.zig:177in nearest public ownertiny.profiling.optionssrc.profiling.options.InterleaveArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:62in nearest public ownertiny.profiling.optionssrc.profiling.options.SamplingArgs.parse[method] — private; no exact target atsrc/profiling/options.zig:201in nearest public ownertiny.profiling.optionssrc.profiling.options.SamplingArgs.value[method] — private; no exact target atsrc/profiling/options.zig:239in nearest public ownertiny.profiling.optionssrc.profiling.options.parseCausalMinTime[function] — private; no exact target atsrc/profiling/options.zig:877in nearest public ownertiny.profiling.optionssrc.profiling.options.parseMeasureRepeat[function] — private; no exact target atsrc/profiling/options.zig:889in nearest public ownertiny.profiling.optionssrc.profiling.options.parseWarmupRepeat[function] — private; no exact target atsrc/profiling/options.zig:903in nearest public ownertiny.profiling.options
Audit
| Definitions | 15 |
|---|---|
| Public names | 15 |
| Members | 19 |
| Version | 26.7.0 |
| Revision | daab053ee433 |