lib/trace/src/profiling/storage.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const bench = @import("bench");
  3 const coz = @import("coz");
  4 const trace = @import("trace");
  5 
  6 pub const scales = [_]usize{ 1_000, 10_000, 100_000 };
  7 
  8 pub const State = struct {
  9     write_path: []const u8,
 10     read_paths: [scales.len][]const u8,
 11 };
 12 
 13 var state: ?State = null;
 14 
 15 pub fn install(new_state: State) void {
 16     state = new_state;
 17 }
 18 
 19 pub fn reset() void {
 20     state = null;
 21 }
 22 
 23 pub fn buildFixture(allocator: std.mem.Allocator, path: []const u8, count: usize) !void {
 24     const manifest = trace.Manifest{ .build_id = "trace-storage-bench" };
 25     const limits = trace.TraceLimits{};
 26     var writer_storage = try trace.TraceWriterStorage.init(
 27         allocator,
 28         trace.TraceWriterLimits.fromOpen(path, manifest, limits),
 29     );
 30     defer writer_storage.deinit(allocator);
 31     writer_storage.activate();
 32     var trace_writer: trace.TraceWriter = .{};
 33     try trace_writer.open(&writer_storage, path, manifest, limits);
 34     defer trace_writer.deinit();
 35     for (0..count) |index| try trace_writer.append(workloadEvent(index));
 36     try trace_writer.finish();
 37 }
 38 
 39 pub fn writeSmall(allocator: std.mem.Allocator) void {
 40     writeScale(allocator, scales[0]);
 41 }
 42 
 43 pub fn writeMedium(allocator: std.mem.Allocator) void {
 44     writeScale(allocator, scales[1]);
 45 }
 46 
 47 pub fn writeLarge(allocator: std.mem.Allocator) void {
 48     writeScale(allocator, scales[2]);
 49 }
 50 
 51 pub fn verifySmall(allocator: std.mem.Allocator) void {
 52     verifyScale(allocator, 0);
 53 }
 54 
 55 pub fn verifyMedium(allocator: std.mem.Allocator) void {
 56     verifyScale(allocator, 1);
 57 }
 58 
 59 pub fn verifyLarge(allocator: std.mem.Allocator) void {
 60     verifyScale(allocator, 2);
 61 }
 62 
 63 fn writeScale(allocator: std.mem.Allocator, count: usize) void {
 64     const installed = state orelse @panic("trace storage benchmark state is not installed");
 65     const manifest = trace.Manifest{ .build_id = "trace-storage-bench" };
 66     const limits = trace.TraceLimits{};
 67     var writer_storage = trace.TraceWriterStorage.init(
 68         allocator,
 69         trace.TraceWriterLimits.fromOpen(installed.write_path, manifest, limits),
 70     ) catch @panic("trace storage benchmark storage failed to initialize");
 71     defer writer_storage.deinit(allocator);
 72     writer_storage.activate();
 73     var trace_writer: trace.TraceWriter = .{};
 74     trace_writer.open(&writer_storage, installed.write_path, manifest, limits) catch
 75         @panic("trace storage benchmark writer failed to open");
 76     defer trace_writer.deinit();
 77     const phase = bench.phaseAt("trace.storage.write", @src());
 78     defer phase.end();
 79     for (0..count) |index| trace_writer.append(workloadEvent(index)) catch
 80         @panic("trace storage benchmark append failed");
 81     trace_writer.finish() catch @panic("trace storage benchmark writer failed to finish");
 82     std.mem.doNotOptimizeAway(count);
 83     coz.progressNamed("trace.storage.write.complete");
 84 }
 85 
 86 fn verifyScale(allocator: std.mem.Allocator, scale_index: usize) void {
 87     const installed = state orelse @panic("trace storage benchmark state is not installed");
 88     const path = installed.read_paths[scale_index];
 89     var reader_storage = trace.TraceReaderStorage.init(
 90         allocator,
 91         trace.TraceReaderLimits.fromOpen(path, .{}),
 92     ) catch @panic("trace storage benchmark reader storage failed to initialize");
 93     defer reader_storage.deinit(allocator);
 94     reader_storage.activate();
 95     var trace_reader: trace.TraceReader = .{};
 96     trace_reader.open(&reader_storage, path) catch
 97         @panic("trace storage benchmark reader failed to open");
 98     defer trace_reader.deinit();
 99     const phase = bench.phaseAt("trace.storage.verify", @src());
100     defer phase.end();
101     const result = trace_reader.verify() catch @panic("trace storage benchmark verification failed");
102     if (result.event_count != scales[scale_index]) @panic("trace storage benchmark witness failed");
103     std.mem.doNotOptimizeAway(result.checksum);
104     coz.progressNamed("trace.storage.verify.complete");
105 }
106 
107 fn workloadEvent(index: usize) trace.Event {
108     return trace.Event.user(
109         .{
110             .thread_id = @intCast(index % 16 + 1),
111             .seq = index + 1,
112         },
113         switch (index % 4) {
114             0 => "compiler.query.start",
115             1 => "compiler.query.cache",
116             2 => "compiler.query.finish",
117             else => "compiler.query.publish",
118         },
119         switch (index % 3) {
120             0 => "{\"protocol\":\"tiny.compiler.query/v1\",\"product_kind\":\"function_summary\",\"elapsed_ns\":1700,\"cache\":\"miss\"}",
121             1 => "{\"protocol\":\"tiny.compiler.query/v1\",\"product_kind\":\"partial_evaluation\",\"elapsed_ns\":2900,\"cache\":\"hit\"}",
122             else => "{\"protocol\":\"tiny.compiler.query/v1\",\"product_kind\":\"source_choir_module\",\"elapsed_ns\":4300,\"cache\":\"hit\"}",
123         },
124     );
125 }
126 
127 test "storage benchmark fixture rolls over and verifies" {
128     const allocator = std.testing.allocator;
129     var tmp = std.testing.tmpDir(.{});
130     defer tmp.cleanup();
131     const root = try tmp.parent_dir.realPathFileAlloc(@import("sys").fs.debugIo(), tmp.sub_path[0..], allocator);
132     defer allocator.free(root);
133     const path = try std.fs.path.join(allocator, &.{ root, "fixture.trace" });
134     defer allocator.free(path);
135     try buildFixture(allocator, path, 20_000);
136     var reader_storage = try trace.TraceReaderStorage.init(
137         allocator,
138         trace.TraceReaderLimits.fromOpen(path, .{}),
139     );
140     defer reader_storage.deinit(allocator);
141     reader_storage.activate();
142     const result = try trace.store.verify(&reader_storage, path);
143     try std.testing.expectEqual(@as(u64, 20_000), result.event_count);
144     try std.testing.expect(result.chunk_count > 1);
145 }