lib/tracy/src/instrumentation.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const build_options = @import("build_options");
  3 const allocator_mod = @import("allocator.zig");
  4 const runtime = @import("runtime.zig");
  5 const summary = @import("summary.zig");
  6 
  7 const SourceLocation = std.builtin.SourceLocation;
  8 const ContextSwitchOptions = runtime.ContextSwitchOptions;
  9 const CpuTopology = runtime.CpuTopology;
 10 const Fiber = runtime.Fiber;
 11 const GpuContext = runtime.GpuContext;
 12 const GpuContextOptions = runtime.GpuContextOptions;
 13 const HardwareSampleKind = runtime.HardwareSampleKind;
 14 const Lock = runtime.Lock;
 15 const PlotConfig = runtime.PlotConfig;
 16 const SampleFrame = runtime.SampleFrame;
 17 const SampleKind = runtime.SampleKind;
 18 const StartOptions = runtime.StartOptions;
 19 const ThreadWakeupOptions = runtime.ThreadWakeupOptions;
 20 const TracedAllocator = allocator_mod.TracedAllocator;
 21 const Zone = runtime.Zone;
 22 
 23 pub fn start(writer: *std.Io.Writer, options: StartOptions) !bool {
 24     return try runtime.start(writer, options);
 25 }
 26 
 27 pub fn stop() void {
 28     runtime.stop();
 29 }
 30 
 31 pub fn tracedAllocator(backing: std.mem.Allocator) TracedAllocator {
 32     return allocator_mod.trace(backing);
 33 }
 34 
 35 pub fn namedAllocator(backing: std.mem.Allocator, name: []const u8) TracedAllocator {
 36     return allocator_mod.traceNamed(backing, name);
 37 }
 38 
 39 pub inline fn zone(comptime name: [:0]const u8) Zone {
 40     return zoneAt(name, @src());
 41 }
 42 
 43 pub inline fn zoneAt(comptime name: [:0]const u8, comptime src: SourceLocation) Zone {
 44     return runtime.zoneAt(name, src, null);
 45 }
 46 
 47 pub inline fn zoneColor(comptime name: [:0]const u8, comptime color: u32) Zone {
 48     return zoneColorAt(name, color, @src());
 49 }
 50 
 51 pub inline fn zoneColorAt(comptime name: [:0]const u8, comptime color: u32, comptime src: SourceLocation) Zone {
 52     return runtime.zoneAt(name, src, color);
 53 }
 54 
 55 pub inline fn lockable(comptime name: [:0]const u8) Lock {
 56     return lockableAt(name, @src());
 57 }
 58 
 59 pub inline fn lockableAt(comptime name: [:0]const u8, comptime src: SourceLocation) Lock {
 60     return runtime.lockableAt(name, src);
 61 }
 62 
 63 pub inline fn sharedLockable(comptime name: [:0]const u8) Lock {
 64     return sharedLockableAt(name, @src());
 65 }
 66 
 67 pub inline fn sharedLockableAt(comptime name: [:0]const u8, comptime src: SourceLocation) Lock {
 68     return runtime.sharedLockableAt(name, src);
 69 }
 70 
 71 pub inline fn frameMark() void {
 72     runtime.frame(null);
 73 }
 74 
 75 pub inline fn frameMarkNamed(comptime name: [:0]const u8) void {
 76     runtime.frame(name);
 77 }
 78 
 79 pub inline fn sample(comptime name: [:0]const u8) void {
 80     runtime.sampleAt(name, .manual, @src());
 81 }
 82 
 83 pub inline fn sampleKind(comptime name: [:0]const u8, kind: SampleKind) void {
 84     runtime.sampleAt(name, kind, @src());
 85 }
 86 
 87 pub inline fn sampleWeighted(comptime name: [:0]const u8, kind: SampleKind, weight: u64) void {
 88     runtime.sampleWeightedAt(name, kind, weight, @src());
 89 }
 90 
 91 pub inline fn sampleStack(name: []const u8, kind: SampleKind, frames: []const SampleFrame) void {
 92     runtime.sampleStack(name, kind, frames);
 93 }
 94 
 95 pub inline fn sampleStackWeighted(name: []const u8, kind: SampleKind, frames: []const SampleFrame, weight: u64) void {
 96     runtime.sampleStackWeighted(name, kind, frames, weight);
 97 }
 98 
 99 pub inline fn newFiber(comptime name: [:0]const u8) Fiber {
100     return runtime.fiber(name, 0);
101 }
102 
103 pub inline fn newFiberHint(comptime name: [:0]const u8, comptime group_hint: i32) Fiber {
104     return runtime.fiber(name, group_hint);
105 }
106 
107 pub inline fn newFiberNamed(name: []const u8) Fiber {
108     return runtime.fiber(name, 0);
109 }
110 
111 pub inline fn newFiberNamedHint(name: []const u8, group_hint: i32) Fiber {
112     return runtime.fiber(name, group_hint);
113 }
114 
115 pub inline fn gpuContext(options: GpuContextOptions) GpuContext {
116     return runtime.gpuContext(options);
117 }
118 
119 pub inline fn contextSwitch(options: ContextSwitchOptions) void {
120     runtime.contextSwitch(options);
121 }
122 
123 pub inline fn threadWakeup(options: ThreadWakeupOptions) void {
124     runtime.threadWakeup(options);
125 }
126 
127 pub inline fn threadContext(thread: u64, name: ?[]const u8) void {
128     runtime.threadContext(thread, name);
129 }
130 
131 pub inline fn threadPid(thread: u64, pid: u64) void {
132     runtime.threadPid(thread, pid);
133 }
134 
135 pub inline fn cpuTopology(topology: CpuTopology) void {
136     runtime.cpuTopology(topology);
137 }
138 
139 pub inline fn systemTime(value: f64) void {
140     runtime.systemTime(value);
141 }
142 
143 pub inline fn systemPower(name: []const u8, delta_uj: u64) void {
144     runtime.systemPower(name, delta_uj);
145 }
146 
147 pub inline fn hardwareSample(kind: HardwareSampleKind, address: u64) void {
148     runtime.hardwareSample(kind, address);
149 }
150 
151 pub inline fn message(text: []const u8) void {
152     runtime.message(text);
153 }
154 
155 pub inline fn appInfo(text: []const u8) void {
156     runtime.appInfo(text);
157 }
158 
159 pub inline fn plotConfig(comptime name: [:0]const u8, config: PlotConfig) void {
160     runtime.plotConfig(name, config);
161 }
162 
163 pub inline fn plot(comptime name: [:0]const u8, value: f64) void {
164     runtime.plotFloat(name, value);
165 }
166 
167 pub inline fn plotFloat(comptime name: [:0]const u8, value: f32) void {
168     runtime.plotFloat(name, @floatCast(value));
169 }
170 
171 pub inline fn plotInt(comptime name: [:0]const u8, value: i64) void {
172     runtime.plotInt(name, value);
173 }
174 
175 pub inline fn alloc(ptr: ?*const anyopaque, size: usize) void {
176     runtime.alloc(ptr, size);
177 }
178 
179 pub inline fn allocNamed(ptr: ?*const anyopaque, size: usize, name: []const u8) void {
180     runtime.allocNamed(ptr, size, name);
181 }
182 
183 pub inline fn free(ptr: ?*const anyopaque) void {
184     runtime.free(ptr);
185 }
186 
187 pub inline fn freeNamed(ptr: ?*const anyopaque, name: []const u8) void {
188     runtime.freeNamed(ptr, name);
189 }
190 
191 pub inline fn freeSized(ptr: ?*const anyopaque, size: usize) void {
192     runtime.freeSized(ptr, size);
193 }
194 
195 pub inline fn freeSizedNamed(ptr: ?*const anyopaque, size: usize, name: []const u8) void {
196     runtime.freeSizedNamed(ptr, size, name);
197 }
198 
199 pub inline fn setThreadName(comptime name: [:0]const u8) void {
200     runtime.threadName(name);
201 }
202 
203 pub inline fn isConnected() bool {
204     return runtime.isActive();
205 }
206 
207 test "instrumentation calls compile" {
208     setThreadName("tracy-test");
209     appInfo("tracy package test");
210     message("tracy message");
211     plotConfig("tracy.plot", .{ .unit = .nanoseconds, .step = true });
212     plot("tracy.plot", 1.25);
213     plotFloat("tracy.plot_float", 1.5);
214     plotInt("tracy.plot_int", 2);
215     frameMark();
216     frameMarkNamed("tracy.frame");
217     sample("tracy.sample");
218     sampleKind("tracy.cpu.sample", .cpu);
219     sampleWeighted("tracy.wall.sample", .wall, 3);
220     sampleStack("tracy.stack.sample", .manual, &.{
221         .{ .name = "root", .function = "root", .file = "root.zig", .line = 1 },
222         .{ .name = "leaf", .function = "leaf", .file = "leaf.zig", .line = 2 },
223     });
224     const profiled_fiber = newFiberHint("tracy.fiber", 7);
225     profiled_fiber.enter();
226     message("tracy fiber message");
227     profiled_fiber.leave();
228     const dynamic_fiber = newFiberNamed("tracy.dynamic_fiber");
229     dynamic_fiber.enter();
230     dynamic_fiber.leave();
231     const profiled_gpu = gpuContext(.{ .name = "tracy.gpu", .context_type = .vulkan, .period = 1.0, .gpu_time = 0 });
232     profiled_gpu.setName("tracy dynamic gpu");
233     profiled_gpu.sync(0);
234     profiled_gpu.calibrate(1, 1);
235     profiled_gpu.annotationName(7, "occupancy");
236     profiled_gpu.annotate(7, 0.5);
237     const gpu_query = profiled_gpu.nextQuery();
238     const gpu_zone = profiled_gpu.zoneQuery("tracy.gpu.zone", gpu_query);
239     gpu_zone.annotate(7, 0.75);
240     gpu_zone.endQueryWithTimes(profiled_gpu.nextQuery(), 1, 3);
241     contextSwitch(.{ .cpu = 0, .prev_thread = 1, .next_thread = 2, .reason = "WrPreempted", .state = "Ready" });
242     threadWakeup(.{ .thread = 1, .cpu = 0, .reason = "Unwait" });
243     threadContext(2, "worker");
244     threadPid(2, 900);
245     cpuTopology(.{ .cpu = 0, .package = 0, .die = 0, .core = 0 });
246     systemTime(0.25);
247     systemPower("package", 100);
248     hardwareSample(.cache_miss, 0x1234);
249 
250     const active_zone = zone("tracy.zone");
251     active_zone.setName("tracy dynamic zone");
252     active_zone.setText("tracy zone text");
253     active_zone.setColor(0x44aa88);
254     active_zone.setValue(42);
255     active_zone.end();
256 
257     const profiled_lock = lockable("tracy.lock");
258     profiled_lock.wait();
259     profiled_lock.obtain();
260     profiled_lock.markAt(@src());
261     profiled_lock.setName("tracy dynamic lock");
262     profiled_lock.release();
263     profiled_lock.terminate();
264 
265     const profiled_shared_lock = sharedLockable("tracy.shared_lock");
266     profiled_shared_lock.sharedWait();
267     profiled_shared_lock.sharedObtain();
268     profiled_shared_lock.sharedRelease();
269     profiled_shared_lock.terminate();
270 
271     alloc(null, 0);
272     allocNamed(null, 0, "tracy.named.alloc");
273     free(null);
274     freeNamed(null, "tracy.named.free");
275     freeSized(null, 0);
276     freeSizedNamed(null, 0, "tracy.named.free_sized");
277     _ = isConnected();
278 }
279 
280 test "enabled trace records analyzable zones" {
281     if (!build_options.enabled) return;
282 
283     var out = std.Io.Writer.Allocating.init(std.testing.allocator);
284     defer out.deinit();
285 
286     try std.testing.expect(try start(&out.writer, .{ .name = "root test" }));
287     defer stop();
288     const active_zone = zone("root.test.zone");
289     active_zone.setValue(12);
290     active_zone.end();
291     const profiled_lock = lockable("root.test.lock");
292     profiled_lock.wait();
293     profiled_lock.obtain();
294     profiled_lock.release();
295     profiled_lock.terminate();
296     message("root test message");
297     sample("root.test.sample");
298     const profiled_fiber = newFiberHint("root.test.fiber", 2);
299     profiled_fiber.enter();
300     message("root fiber message");
301     profiled_fiber.leave();
302     contextSwitch(.{ .cpu = 0, .prev_thread = 1, .next_thread = 2, .reason = "WrPreempted", .state = "Ready" });
303     threadWakeup(.{ .thread = 1, .cpu = 0, .reason = "Unwait" });
304     plotInt("root.test.plot", 7);
305     stop();
306 
307     var analyzer = summary.Analyzer.init(std.testing.allocator);
308     defer analyzer.deinit();
309     try analyzer.ingestJsonlBytes(out.written());
310     try std.testing.expectEqual(@as(u64, 1), analyzer.counters.completed_zones);
311     try std.testing.expectEqual(@as(u64, 2), analyzer.counters.messages);
312     try std.testing.expectEqual(@as(u64, 1), analyzer.samples.counters.samples);
313     try std.testing.expectEqual(@as(u64, 1), analyzer.fibers.counters.names);
314     try std.testing.expectEqual(@as(u64, 1), analyzer.fibers.counters.enters);
315     try std.testing.expectEqual(@as(u64, 1), analyzer.fibers.counters.leaves);
316     try std.testing.expectEqual(@as(u64, 1), analyzer.context.counters.switches);
317     try std.testing.expectEqual(@as(u64, 1), analyzer.context.counters.wakeups);
318     try std.testing.expectEqual(@as(u64, 1), analyzer.counters.plots);
319     try std.testing.expectEqual(@as(usize, 1), analyzer.locks.locks.count());
320     try std.testing.expectEqual(@as(u64, 1), analyzer.locks.counters.completed_waits);
321     try std.testing.expectEqual(@as(u64, 1), analyzer.locks.counters.completed_holds);
322 }
323 
324 test {
325     std.testing.refAllDecls(@This());
326 }