Skip to content

Commit f22b1f4

Browse files
committed
feat: add analysis instrument
1 parent 8a3043f commit f22b1f4

File tree

6 files changed

+111
-19
lines changed

6 files changed

+111
-19
lines changed

src/instruments/analysis.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const shared = @import("../shared.zig");
2+
const fifo_instrument = @import("fifo_instrument.zig");
3+
4+
const AnalysisError = error{ModeError};
5+
6+
pub const AnalysisInstrument = fifo_instrument.FifoInstrument(.Analysis, AnalysisError);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const std = @import("std");
2+
const runner_fifo = @import("../runner_fifo.zig");
3+
const shared = @import("../shared.zig");
4+
5+
/// Creates a complete FIFO-based instrument struct that validates a specific integration mode
6+
pub fn FifoInstrument(comptime mode: shared.IntegrationMode, comptime error_type: anytype) type {
7+
return struct {
8+
fifo: runner_fifo.RunnerFifo,
9+
10+
const Self = @This();
11+
12+
pub fn init(allocator: std.mem.Allocator) !Self {
13+
var fifo = try runner_fifo.RunnerFifo.init(allocator);
14+
15+
// Get the instrumentation mode from the runner
16+
const detected_mode = fifo.get_integration_mode() catch |err| {
17+
fifo.deinit();
18+
return err;
19+
};
20+
21+
// Only accept if the runner is in the correct mode
22+
if (detected_mode != mode) {
23+
fifo.deinit();
24+
return error_type.ModeError;
25+
}
26+
27+
return Self{ .fifo = fifo };
28+
}
29+
30+
pub fn deinit(self: *Self) void {
31+
self.fifo.deinit();
32+
}
33+
34+
pub fn send_version(self: *Self, protocol_version: u64) !void {
35+
try self.fifo.send_version(protocol_version);
36+
}
37+
38+
pub fn start_benchmark(self: *Self) !void {
39+
try self.fifo.start_benchmark();
40+
}
41+
42+
pub fn stop_benchmark(self: *Self) !void {
43+
try self.fifo.stop_benchmark();
44+
}
45+
46+
pub fn set_executed_benchmark(self: *Self, pid: u32, uri: [*c]const u8) !void {
47+
try self.fifo.set_executed_benchmark(pid, uri);
48+
}
49+
50+
pub fn set_integration(self: *Self, name: [*c]const u8, version: [*c]const u8) !void {
51+
try self.fifo.set_integration(name, version);
52+
}
53+
54+
pub fn add_marker(self: *Self, pid: u32, marker: shared.MarkerType) !void {
55+
try self.fifo.add_marker(pid, marker);
56+
}
57+
};
58+
}

src/instruments/perf.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
const std = @import("std");
2-
const fifo = @import("../fifo.zig");
31
const shared = @import("../shared.zig");
4-
const runner_fifo = @import("../runner_fifo.zig");
2+
const fifo_instrument = @import("fifo_instrument.zig");
53

6-
pub const PerfInstrument = runner_fifo.RunnerFifo;
4+
const PerfError = error{ModeError};
5+
6+
pub const PerfInstrument = fifo_instrument.FifoInstrument(.Perf, PerfError);

src/instruments/root.zig

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
11
const std = @import("std");
2-
const builtin = @import("builtin");
32
const perf = @import("perf.zig");
3+
const analysis = @import("analysis.zig");
44
const valgrind = @import("valgrind.zig");
55
const shared = @import("../shared.zig");
66
const ValgrindInstrument = valgrind.ValgrindInstrument;
7+
const PerfInstrument = perf.PerfInstrument;
8+
const AnalysisInstrument = analysis.AnalysisInstrument;
79

810
pub const InstrumentHooks = union(enum) {
911
valgrind: ValgrindInstrument,
10-
perf: perf.PerfInstrument,
12+
perf: PerfInstrument,
13+
analysis: AnalysisInstrument,
1114
none: void,
1215

1316
const Self = @This();
1417

1518
pub fn init(allocator: std.mem.Allocator) !Self {
16-
if (ValgrindInstrument.is_instrumented()) {
17-
return Self{ .valgrind = ValgrindInstrument.init(allocator) };
18-
}
19+
if (ValgrindInstrument.init(allocator)) |valgrind_inst| {
20+
return Self{ .valgrind = valgrind_inst };
21+
} else |_| {}
1922

20-
var perf_inst = perf.PerfInstrument.init(allocator) catch {
21-
return Self{ .none = {} };
22-
};
23-
if (perf_inst.is_instrumented()) {
23+
if (AnalysisInstrument.init(allocator)) |analysis_inst| {
24+
return Self{ .analysis = analysis_inst };
25+
} else |_| {}
26+
27+
if (PerfInstrument.init(allocator)) |perf_inst| {
2428
return Self{ .perf = perf_inst };
25-
}
29+
} else |_| {}
2630

2731
return Self{ .none = {} };
2832
}
@@ -31,17 +35,16 @@ pub const InstrumentHooks = union(enum) {
3135
switch (self.*) {
3236
.valgrind => {},
3337
.perf => self.perf.deinit(),
38+
.analysis => self.analysis.deinit(),
3439
.none => {},
3540
}
3641
}
3742

3843
pub inline fn is_instrumented(self: *Self) bool {
3944
return switch (self.*) {
4045
.valgrind => ValgrindInstrument.is_instrumented(),
41-
.perf => |perf_inst| {
42-
var mutable_perf = perf_inst;
43-
return mutable_perf.is_instrumented();
44-
},
46+
.perf => true,
47+
.analysis => true,
4548
.none => false,
4649
};
4750
}
@@ -51,6 +54,8 @@ pub const InstrumentHooks = union(enum) {
5154
return self.perf.start_benchmark();
5255
} else if (self.* == .valgrind) {
5356
return ValgrindInstrument.start_benchmark();
57+
} else if (self.* == .analysis) {
58+
return self.analysis.start_benchmark();
5459
}
5560
}
5661

@@ -59,13 +64,16 @@ pub const InstrumentHooks = union(enum) {
5964
return ValgrindInstrument.stop_benchmark();
6065
} else if (self.* == .perf) {
6166
return self.perf.stop_benchmark();
67+
} else if (self.* == .analysis) {
68+
return self.analysis.stop_benchmark();
6269
}
6370
}
6471

6572
pub inline fn set_executed_benchmark(self: *Self, pid: u32, uri: [*c]const u8) !void {
6673
switch (self.*) {
6774
.valgrind => ValgrindInstrument.set_executed_benchmark(pid, uri),
6875
.perf => try self.perf.set_executed_benchmark(pid, uri),
76+
.analysis => try self.analysis.set_executed_benchmark(pid, uri),
6977
.none => {},
7078
}
7179
}
@@ -74,13 +82,16 @@ pub const InstrumentHooks = union(enum) {
7482
switch (self.*) {
7583
.valgrind => try self.valgrind.set_integration(name, version),
7684
.perf => try self.perf.set_integration(name, version),
85+
.analysis => try self.analysis.set_integration(name, version),
7786
.none => {},
7887
}
7988
}
8089

8190
pub inline fn add_marker(self: *Self, pid: u32, marker: shared.MarkerType) !void {
8291
if (self.* == .perf) {
8392
return self.perf.add_marker(pid, marker);
93+
} else if (self.* == .analysis) {
94+
return self.analysis.add_marker(pid, marker);
8495
}
8596
}
8697
};

src/instruments/valgrind.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ pub const ValgrindInstrument = struct {
66
allocator: std.mem.Allocator,
77
const Self = @This();
88

9-
pub fn init(allocator: std.mem.Allocator) Self {
9+
pub fn init(allocator: std.mem.Allocator) !Self {
10+
if (!ValgrindInstrument.is_instrumented()) {
11+
return error.NotInstrumented;
12+
}
13+
1014
return Self{
1115
.allocator = allocator,
1216
};

src/runner_fifo.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ pub const RunnerFifo = struct {
9191
try self.writer.sendCmd(fifo.Command{ .SetVersion = protocol_version });
9292
try self.reader.waitForAck(null);
9393
}
94+
95+
pub fn get_integration_mode(self: *Self) !shared.IntegrationMode {
96+
// NOTE: Other messages send data to the runner, and expect an ACK response (see `sendCmd`). This
97+
// command expects the runner to respond with data, so have to write and read directly.
98+
try self.writer.sendCmd(fifo.Command.GetIntegrationMode);
99+
const response = try self.reader.waitForResponse(null);
100+
defer response.deinit(self.allocator);
101+
102+
if (response == .IntegrationModeResponse) {
103+
return response.IntegrationModeResponse;
104+
}
105+
return error.UnexpectedResponse;
106+
}
94107
};
95108

96109
test "test runner fifo" {

0 commit comments

Comments
 (0)