lib/tracy/src/cli/args/flame.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const tracy = @import("../../root.zig");
3 const scalar = @import("scalar.zig");
4 const types = @import("types.zig");
5
6 pub fn parse(args: []const []const u8) !types.FlameArgs {
7 if (args.len == 0) return error.InvalidArguments;
8 var parsed = types.FlameArgs{ .path = args[0] };
9 var around_ns: ?u64 = null;
10 var window_ns: ?u64 = null;
11 var index: usize = 1;
12 while (index < args.len) : (index += 1) {
13 if (std.mem.eql(u8, args[index], "--format")) {
14 index += 1;
15 if (index >= args.len) return error.InvalidArguments;
16 if (std.mem.eql(u8, args[index], "text")) {
17 parsed.format = .text;
18 } else if (std.mem.eql(u8, args[index], "jsonl")) {
19 parsed.format = .jsonl;
20 } else if (std.mem.eql(u8, args[index], "folded")) {
21 parsed.format = .folded;
22 } else {
23 return error.UnsupportedFormat;
24 }
25 } else if (std.mem.eql(u8, args[index], "--top")) {
26 index += 1;
27 if (index >= args.len) return error.InvalidArguments;
28 parsed.options.top = try scalar.parsePositiveUsize(args[index]);
29 } else if (std.mem.eql(u8, args[index], "--sort")) {
30 index += 1;
31 if (index >= args.len) return error.InvalidArguments;
32 parsed.options.sort = tracy.flame.Sort.fromName(args[index]) orelse return error.UnsupportedSort;
33 } else if (std.mem.eql(u8, args[index], "--max-depth")) {
34 index += 1;
35 if (index >= args.len) return error.InvalidArguments;
36 parsed.options.max_depth = try scalar.parseUsize(args[index]);
37 } else if (std.mem.eql(u8, args[index], "--min-ns")) {
38 index += 1;
39 if (index >= args.len) return error.InvalidArguments;
40 parsed.options.min_ns = try scalar.parseU64(args[index]);
41 } else if (std.mem.eql(u8, args[index], "--thread")) {
42 index += 1;
43 if (index >= args.len) return error.InvalidArguments;
44 parsed.options.thread = try scalar.parseU64(args[index]);
45 } else if (std.mem.eql(u8, args[index], "--since-ns")) {
46 index += 1;
47 if (index >= args.len) return error.InvalidArguments;
48 parsed.options.since_ns = try scalar.parseU64(args[index]);
49 } else if (std.mem.eql(u8, args[index], "--until-ns")) {
50 index += 1;
51 if (index >= args.len) return error.InvalidArguments;
52 parsed.options.until_ns = try scalar.parseU64(args[index]);
53 } else if (std.mem.eql(u8, args[index], "--around-ns")) {
54 index += 1;
55 if (index >= args.len) return error.InvalidArguments;
56 around_ns = try scalar.parseU64(args[index]);
57 } else if (std.mem.eql(u8, args[index], "--window-ns")) {
58 index += 1;
59 if (index >= args.len) return error.InvalidArguments;
60 window_ns = try scalar.parseU64(args[index]);
61 } else if (std.mem.eql(u8, args[index], "--match")) {
62 index += 1;
63 if (index >= args.len) return error.InvalidArguments;
64 parsed.options.match = args[index];
65 } else {
66 return error.UnknownArgument;
67 }
68 }
69 if (around_ns) |center| {
70 if (parsed.options.since_ns != null or parsed.options.until_ns != null) return error.InvalidArguments;
71 const width = window_ns orelse 1_000_000;
72 const half = width / 2;
73 parsed.options.since_ns = if (center > half) center - half else 0;
74 parsed.options.until_ns = center +| (width - half);
75 } else if (window_ns != null) {
76 return error.InvalidArguments;
77 }
78 if (parsed.options.since_ns != null and parsed.options.until_ns != null and parsed.options.since_ns.? > parsed.options.until_ns.?) {
79 return error.InvalidArguments;
80 }
81 return parsed;
82 }
83
84 test "flame args parse filters window and folded format" {
85 const parsed = try parse(&.{
86 "events.jsonl",
87 "--format",
88 "folded",
89 "--top",
90 "12",
91 "--sort",
92 "name",
93 "--max-depth",
94 "4",
95 "--min-ns",
96 "50",
97 "--thread",
98 "7",
99 "--around-ns",
100 "1000",
101 "--window-ns",
102 "200",
103 "--match",
104 "phase",
105 });
106 try std.testing.expectEqualStrings("events.jsonl", parsed.path);
107 try std.testing.expectEqual(types.FlameFormat.folded, parsed.format);
108 try std.testing.expectEqual(@as(usize, 12), parsed.options.top);
109 try std.testing.expectEqual(tracy.flame.Sort.name, parsed.options.sort);
110 try std.testing.expectEqual(@as(usize, 4), parsed.options.max_depth);
111 try std.testing.expectEqual(@as(u64, 50), parsed.options.min_ns);
112 try std.testing.expectEqual(@as(?u64, 7), parsed.options.thread);
113 try std.testing.expectEqual(@as(?u64, 900), parsed.options.since_ns);
114 try std.testing.expectEqual(@as(?u64, 1100), parsed.options.until_ns);
115 try std.testing.expectEqualStrings("phase", parsed.options.match.?);
116 }