lib/tldr/src/profiling/collect/parse/suite/relink.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const collect = @import("../../root.zig");
  2 const collect_base = collect.base;
  3 const std = collect_base.std;
  4 const check = collect_base.check;
  5 const discover = collect_base.discover;
  6 const relink = collect_base.relink;
  7 
  8 const model = collect.model;
  9 const parse = @import("../root.zig");
 10 
 11 pub fn parseRelinkConfig(allocator: model.Allocator, args: []const []const u8) !model.RelinkConfig {
 12     if (args.len == 0) return error.InvalidArguments;
 13     if (std.mem.startsWith(u8, args[0], "-")) return error.InvalidArguments;
 14     var platforms: std.ArrayList(discover.Platform) = .empty;
 15     var patterns: std.ArrayList([]const u8) = .empty;
 16     var config = model.RelinkConfig{
 17         .discovery = .{
 18             .root = args[0],
 19             .platforms = &.{},
 20             .patterns = &.{},
 21         },
 22     };
 23     var index: usize = 1;
 24     while (index < args.len) {
 25         const arg = args[index];
 26         if (std.mem.eql(u8, arg, "--format")) {
 27             index += 1;
 28             if (index >= args.len) return error.InvalidArguments;
 29             config.discovery.format = discover.SuiteFormat.parse(args[index]) orelse return error.InvalidArguments;
 30             index += 1;
 31         } else if (std.mem.eql(u8, arg, "--platform")) {
 32             index += 1;
 33             if (index >= args.len) return error.InvalidArguments;
 34             try platforms.append(allocator, discover.Platform.parse(args[index]) orelse return error.InvalidArguments);
 35             index += 1;
 36         } else if (std.mem.eql(u8, arg, "--case")) {
 37             index += 1;
 38             if (index >= args.len) return error.InvalidArguments;
 39             try patterns.append(allocator, args[index]);
 40             index += 1;
 41         } else if (std.mem.eql(u8, arg, "--tldr-command")) {
 42             index += 1;
 43             if (index >= args.len) return error.InvalidArguments;
 44             config.tldr_command = try check.parseCommand(allocator, args[index]);
 45             index += 1;
 46         } else if (std.mem.eql(u8, arg, "--tmp-dir")) {
 47             index += 1;
 48             if (index >= args.len) return error.InvalidArguments;
 49             config.tmp_dir = args[index];
 50             index += 1;
 51         } else if (std.mem.eql(u8, arg, "--warmup")) {
 52             index += 1;
 53             if (index >= args.len) return error.InvalidArguments;
 54             config.warmup = try parse.parseNonNegativeUsize(args[index]);
 55             index += 1;
 56         } else if (std.mem.eql(u8, arg, "--min-runs")) {
 57             index += 1;
 58             if (index >= args.len) return error.InvalidArguments;
 59             config.min_runs = try parse.parsePositiveUsize(args[index]);
 60             index += 1;
 61         } else if (std.mem.eql(u8, arg, "--max-runs")) {
 62             index += 1;
 63             if (index >= args.len) return error.InvalidArguments;
 64             config.max_runs = try parse.parsePositiveUsize(args[index]);
 65             index += 1;
 66         } else if (std.mem.eql(u8, arg, "--min-time")) {
 67             index += 1;
 68             if (index >= args.len) return error.InvalidArguments;
 69             config.min_time_s = try parse.parseNonNegativeFloat(args[index]);
 70             index += 1;
 71         } else if (std.mem.eql(u8, arg, "--timeout")) {
 72             index += 1;
 73             if (index >= args.len) return error.InvalidArguments;
 74             config.timeout_s = try parse.parsePositiveFloat(args[index]);
 75             index += 1;
 76         } else if (std.mem.eql(u8, arg, "--no-fork")) {
 77             config.no_fork = true;
 78             index += 1;
 79         } else if (std.mem.eql(u8, arg, "--output-csv")) {
 80             index += 1;
 81             if (index >= args.len) return error.InvalidArguments;
 82             config.output_csv = args[index];
 83             index += 1;
 84         } else if (std.mem.eql(u8, arg, "--output-jsonl")) {
 85             index += 1;
 86             if (index >= args.len) return error.InvalidArguments;
 87             config.output_jsonl = args[index];
 88             index += 1;
 89         } else if (std.mem.eql(u8, arg, "--output-report-markdown")) {
 90             index += 1;
 91             if (index >= args.len) return error.InvalidArguments;
 92             config.output_report_markdown = args[index];
 93             index += 1;
 94         } else {
 95             return error.InvalidArguments;
 96         }
 97     }
 98     if (config.max_runs < config.min_runs) return error.InvalidArguments;
 99     config.discovery.platforms = try platforms.toOwnedSlice(allocator);
100     config.discovery.patterns = try patterns.toOwnedSlice(allocator);
101     return config;
102 }
103 
104 test "relink config defaults" {
105     var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);
106     defer arena_state.deinit();
107     const arena = arena_state.allocator();
108     const config = try parseRelinkConfig(arena, &.{"zig-out/linker-suites"});
109     try std.testing.expectEqualStrings("zig-out/linker-suites", config.discovery.root);
110     try std.testing.expectEqual(discover.SuiteFormat.auto, config.discovery.format);
111     try std.testing.expectEqual(@as(usize, 0), config.discovery.platforms.len);
112     try std.testing.expectEqual(@as(usize, 0), config.discovery.patterns.len);
113     try std.testing.expectEqualStrings("tldr-link", config.tldr_command[0]);
114     try std.testing.expectEqualStrings(check.default_tmp_dir, config.tmp_dir);
115     try std.testing.expectEqual(@as(usize, relink.default_warmup_runs), config.warmup);
116     try std.testing.expectEqual(@as(usize, relink.default_min_runs), config.min_runs);
117     try std.testing.expectEqual(@as(usize, relink.default_max_runs), config.max_runs);
118     try std.testing.expectEqual(@as(f64, relink.default_min_time_s), config.min_time_s);
119     try std.testing.expect(config.timeout_s == null);
120     try std.testing.expect(!config.no_fork);
121 }
122 
123 test "relink config parses outputs filters and timing" {
124     var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);
125     defer arena_state.deinit();
126     const arena = arena_state.allocator();
127     const config = try parseRelinkConfig(arena, &.{ "suite", "--format", "lld", "--platform", "elf", "--case", "tldr-*", "--tldr-command", "/tmp/tldr-link --flag", "--tmp-dir", ".zig-cache/tmp", "--warmup", "0", "--min-runs", "2", "--max-runs", "5", "--min-time", "0", "--timeout", "1.25", "--no-fork", "--output-csv", "relink.csv", "--output-jsonl", "relink.jsonl", "--output-report-markdown", "relink.md" });
128     try std.testing.expectEqual(discover.SuiteFormat.lld, config.discovery.format);
129     try std.testing.expectEqualSlices(discover.Platform, &.{.elf}, config.discovery.platforms);
130     try std.testing.expectEqualStrings("tldr-*", config.discovery.patterns[0]);
131     try std.testing.expectEqualStrings("/tmp/tldr-link", config.tldr_command[0]);
132     try std.testing.expectEqualStrings("--flag", config.tldr_command[1]);
133     try std.testing.expectEqualStrings(".zig-cache/tmp", config.tmp_dir);
134     try std.testing.expectEqual(@as(usize, 0), config.warmup);
135     try std.testing.expectEqual(@as(usize, 2), config.min_runs);
136     try std.testing.expectEqual(@as(usize, 5), config.max_runs);
137     try std.testing.expectEqual(@as(f64, 0), config.min_time_s);
138     try std.testing.expectEqual(@as(f64, 1.25), config.timeout_s.?);
139     try std.testing.expect(config.no_fork);
140     try std.testing.expectEqualStrings("relink.csv", config.output_csv.?);
141     try std.testing.expectEqualStrings("relink.jsonl", config.output_jsonl.?);
142     try std.testing.expectEqualStrings("relink.md", config.output_report_markdown.?);
143 }
144 
145 test "relink config rejects invalid timing" {
146     try std.testing.expectError(error.InvalidArguments, parseRelinkConfig(std.testing.allocator, &.{ "suite", "--min-time", "-1" }));
147     try std.testing.expectError(error.InvalidArguments, parseRelinkConfig(std.testing.allocator, &.{ "suite", "--min-runs", "3", "--max-runs", "2" }));
148 }