lib/chant/src/profiling/versus/runner.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const bench = @import("bench");
3 const chant = @import("chant");
4 const choir = @import("choir");
5 const sys = @import("sys");
6
7 const compiler = @import("compiler.zig");
8 const event = @import("event.zig");
9 const kernel_mod = @import("kernel.zig");
10 const measure = @import("measure.zig");
11 const options_mod = @import("options.zig");
12 const row = @import("row.zig");
13 const timer_mod = @import("timer.zig");
14
15 const jsonl = choir.versus.jsonl;
16 const oracle = choir.versus.oracle;
17 const workload_mod = choir.versus.workload;
18
19 const Allocator = std.mem.Allocator;
20 const Workload = workload_mod.Workload;
21
22 pub fn run(arena: Allocator, gpa: Allocator, environ: std.process.Environ, args: []const []const u8) !u8 {
23 var stdout_buffer: [16384]u8 = undefined;
24 var stdout = sys.stdio.stdout().writer(sys.stdio.debugIo(), &stdout_buffer);
25 defer stdout.interface.flush() catch {};
26 const out = &stdout.interface;
27
28 const options = options_mod.parse(args) orelse {
29 try bench.pretty.write(out, .{ .text = options_mod.usage_text }, .{});
30 return 0;
31 };
32
33 try event.writeRunStart(out, options);
34 try jsonl.writeMeta(out, "harness", "x86_64-linux", "chant frontend lane over the shared versus corpus");
35
36 sys.fs.createDirPath(options.workdir) catch {};
37
38 for (workload_mod.battery) |workload| {
39 if (options.workload) |only| {
40 if (!std.mem.eql(u8, workload.name, only)) continue;
41 }
42 try runWorkload(arena, gpa, out, environ, workload, options);
43 }
44 try event.writeRunEnd(out, options);
45 return 0;
46 }
47
48 fn runWorkload(
49 arena: Allocator,
50 gpa: Allocator,
51 out: *std.Io.Writer,
52 environ: std.process.Environ,
53 workload: Workload,
54 options: options_mod.Options,
55 ) !void {
56 var ctx = try choir.Context.init(arena, choir.Context.Limits.standard);
57 defer ctx.deinit(arena);
58 try choir.dialects.registerAllDialects(&ctx);
59
60 var timer = timer_mod.start();
61 var compile_diagnostic: chant.Diagnostic = .{};
62 const unit = compiler.compileCorpus(gpa, arena, &ctx, environ, workload, options, &compile_diagnostic) catch |err| {
63 const reason = if (compile_diagnostic.message.len != 0)
64 try std.fmt.allocPrint(arena, "{s}: {s}", .{ @errorName(err), compile_diagnostic.message })
65 else
66 @errorName(err);
67 try row.skipped(out, workload, reason);
68 return;
69 };
70 const symbol = workload.kind.symbol();
71 var lowered = false;
72 for (unit.lowered.items) |name| {
73 if (std.mem.eql(u8, name, symbol)) lowered = true;
74 }
75 if (!lowered) {
76 var reason: []const u8 = "kernel not lowered";
77 for (unit.skipped.items) |skipped| {
78 if (std.mem.eql(u8, skipped.name, symbol)) reason = @errorName(skipped.reason);
79 }
80 try row.skipped(out, workload, reason);
81 return;
82 }
83
84 {
85 var pass_manager = choir.passes.PassManager.init(arena);
86 defer pass_manager.deinit();
87 choir.passes.addDefaultOptimizationPipeline(&pass_manager) catch |err| {
88 try row.skipped(out, workload, @errorName(err));
89 return;
90 };
91 const pass_result = pass_manager.run(unit.module.op, &ctx);
92 if (pass_result != .success) {
93 try row.skipped(out, workload, "pipeline failed");
94 return;
95 }
96 }
97
98 var backend = try choir.backends.x86_64.backend.Backend.init(arena, &ctx, .standard);
99 defer backend.deinit();
100 const compiled = backend.compile(unit.module.op) catch |err| {
101 try row.skipped(out, workload, @errorName(err));
102 return;
103 };
104 const compile_ns = timer_mod.read(&timer);
105
106 try jsonl.writeRow(out, .{
107 .system = row.system,
108 .workload = workload.name,
109 .metric = .compile_ns,
110 .samples = 1,
111 .median_ns = compile_ns,
112 .p10_ns = compile_ns,
113 .p90_ns = compile_ns,
114 .flops = workload.flops(),
115 .moved_bytes = workload.movedBytes(),
116 });
117
118 const kernel = (try kernel_mod.open(&backend.runtime, compiled, workload.kind)) orelse {
119 try row.skipped(out, workload, "kernel symbol missing after compile");
120 return;
121 };
122
123 var buffers = try oracle.Buffers.alloc(arena, workload);
124 try measure.run(arena, out, workload, &buffers, kernel, options);
125 }