master
1const std = @import("std");
2const builtin = @import("builtin");
3const build_options = @import("build_options");
4
5pub const enable = if (builtin.is_test) false else build_options.enable_tracy;
6pub const enable_allocation = enable and build_options.enable_tracy_allocation;
7pub const enable_callstack = enable and build_options.enable_tracy_callstack;
8pub const callstack_depth = if (enable_callstack and build_options.tracy_callstack_depth > 0) build_options.tracy_callstack_depth else 10;
9
10const ___tracy_c_zone_context = extern struct {
11 id: u32,
12 active: c_int,
13
14 pub inline fn end(self: @This()) void {
15 ___tracy_emit_zone_end(self);
16 }
17
18 pub inline fn addText(self: @This(), text: []const u8) void {
19 ___tracy_emit_zone_text(self, text.ptr, text.len);
20 }
21
22 pub inline fn setName(self: @This(), name: []const u8) void {
23 ___tracy_emit_zone_name(self, name.ptr, name.len);
24 }
25
26 pub inline fn setColor(self: @This(), color: u32) void {
27 ___tracy_emit_zone_color(self, color);
28 }
29
30 pub inline fn setValue(self: @This(), value: u64) void {
31 ___tracy_emit_zone_value(self, value);
32 }
33};
34
35pub const Ctx = if (enable) ___tracy_c_zone_context else struct {
36 pub inline fn end(self: @This()) void {
37 _ = self;
38 }
39
40 pub inline fn addText(self: @This(), text: []const u8) void {
41 _ = self;
42 _ = text;
43 }
44
45 pub inline fn setName(self: @This(), name: []const u8) void {
46 _ = self;
47 _ = name;
48 }
49
50 pub inline fn setColor(self: @This(), color: u32) void {
51 _ = self;
52 _ = color;
53 }
54
55 pub inline fn setValue(self: @This(), value: u64) void {
56 _ = self;
57 _ = value;
58 }
59};
60
61pub inline fn trace(comptime src: std.builtin.SourceLocation) Ctx {
62 if (!enable) return .{};
63
64 const global = struct {
65 const loc: ___tracy_source_location_data = .{
66 .name = null,
67 .function = src.fn_name.ptr,
68 .file = src.file.ptr,
69 .line = src.line,
70 .color = 0,
71 };
72 };
73
74 if (enable_callstack) {
75 return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1);
76 } else {
77 return ___tracy_emit_zone_begin(&global.loc, 1);
78 }
79}
80
81pub inline fn traceNamed(comptime src: std.builtin.SourceLocation, comptime name: [:0]const u8) Ctx {
82 if (!enable) return .{};
83
84 const global = struct {
85 const loc: ___tracy_source_location_data = .{
86 .name = name.ptr,
87 .function = src.fn_name.ptr,
88 .file = src.file.ptr,
89 .line = src.line,
90 .color = 0,
91 };
92 };
93
94 if (enable_callstack) {
95 return ___tracy_emit_zone_begin_callstack(&global.loc, callstack_depth, 1);
96 } else {
97 return ___tracy_emit_zone_begin(&global.loc, 1);
98 }
99}
100
101pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) {
102 return TracyAllocator(null).init(allocator);
103}
104
105pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
106 return struct {
107 parent_allocator: std.mem.Allocator,
108
109 const Self = @This();
110
111 pub fn init(parent_allocator: std.mem.Allocator) Self {
112 return .{
113 .parent_allocator = parent_allocator,
114 };
115 }
116
117 pub fn allocator(self: *Self) std.mem.Allocator {
118 return .{
119 .ptr = self,
120 .vtable = &.{
121 .alloc = allocFn,
122 .resize = resizeFn,
123 .remap = remapFn,
124 .free = freeFn,
125 },
126 };
127 }
128
129 fn allocFn(ptr: *anyopaque, len: usize, alignment: std.mem.Alignment, ret_addr: usize) ?[*]u8 {
130 const self: *Self = @ptrCast(@alignCast(ptr));
131 const result = self.parent_allocator.rawAlloc(len, alignment, ret_addr);
132 if (result) |memory| {
133 if (len != 0) {
134 if (name) |n| {
135 allocNamed(memory, len, n);
136 } else {
137 alloc(memory, len);
138 }
139 }
140 } else {
141 messageColor("allocation failed", 0xFF0000);
142 }
143 return result;
144 }
145
146 fn resizeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) bool {
147 const self: *Self = @ptrCast(@alignCast(ptr));
148 if (self.parent_allocator.rawResize(memory, alignment, new_len, ret_addr)) {
149 if (name) |n| {
150 freeNamed(memory.ptr, n);
151 allocNamed(memory.ptr, new_len, n);
152 } else {
153 free(memory.ptr);
154 alloc(memory.ptr, new_len);
155 }
156
157 return true;
158 }
159
160 // during normal operation the compiler hits this case thousands of times due to this
161 // emitting messages for it is both slow and causes clutter
162 return false;
163 }
164
165 fn remapFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 {
166 const self: *Self = @ptrCast(@alignCast(ptr));
167 if (self.parent_allocator.rawRemap(memory, alignment, new_len, ret_addr)) |new_memory| {
168 if (name) |n| {
169 freeNamed(memory.ptr, n);
170 allocNamed(new_memory, new_len, n);
171 } else {
172 free(memory.ptr);
173 alloc(new_memory, new_len);
174 }
175 return new_memory;
176 } else {
177 messageColor("reallocation failed", 0xFF0000);
178 return null;
179 }
180 }
181
182 fn freeFn(ptr: *anyopaque, memory: []u8, alignment: std.mem.Alignment, ret_addr: usize) void {
183 const self: *Self = @ptrCast(@alignCast(ptr));
184 self.parent_allocator.rawFree(memory, alignment, ret_addr);
185 // this condition is to handle free being called on an empty slice that was never even allocated
186 // example case: `std.process.getSelfExeSharedLibPaths` can return `&[_][:0]u8{}`
187 if (memory.len != 0) {
188 if (name) |n| {
189 freeNamed(memory.ptr, n);
190 } else {
191 free(memory.ptr);
192 }
193 }
194 }
195 };
196}
197
198// This function only accepts comptime-known strings, see `messageCopy` for runtime strings
199pub inline fn message(comptime msg: [:0]const u8) void {
200 if (!enable) return;
201 ___tracy_emit_messageL(msg.ptr, if (enable_callstack) callstack_depth else 0);
202}
203
204// This function only accepts comptime-known strings, see `messageColorCopy` for runtime strings
205pub inline fn messageColor(comptime msg: [:0]const u8, color: u32) void {
206 if (!enable) return;
207 ___tracy_emit_messageLC(msg.ptr, color, if (enable_callstack) callstack_depth else 0);
208}
209
210pub inline fn messageCopy(msg: []const u8) void {
211 if (!enable) return;
212 ___tracy_emit_message(msg.ptr, msg.len, if (enable_callstack) callstack_depth else 0);
213}
214
215pub inline fn messageColorCopy(msg: [:0]const u8, color: u32) void {
216 if (!enable) return;
217 ___tracy_emit_messageC(msg.ptr, msg.len, color, if (enable_callstack) callstack_depth else 0);
218}
219
220pub inline fn frameMark() void {
221 if (!enable) return;
222 ___tracy_emit_frame_mark(null);
223}
224
225pub inline fn frameMarkNamed(comptime name: [:0]const u8) void {
226 if (!enable) return;
227 ___tracy_emit_frame_mark(name.ptr);
228}
229
230pub inline fn namedFrame(comptime name: [:0]const u8) Frame(name) {
231 frameMarkStart(name);
232 return .{};
233}
234
235pub fn Frame(comptime name: [:0]const u8) type {
236 return struct {
237 pub fn end(_: @This()) void {
238 frameMarkEnd(name);
239 }
240 };
241}
242
243inline fn frameMarkStart(comptime name: [:0]const u8) void {
244 if (!enable) return;
245 ___tracy_emit_frame_mark_start(name.ptr);
246}
247
248inline fn frameMarkEnd(comptime name: [:0]const u8) void {
249 if (!enable) return;
250 ___tracy_emit_frame_mark_end(name.ptr);
251}
252
253extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void;
254extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void;
255
256inline fn alloc(ptr: [*]u8, len: usize) void {
257 if (!enable) return;
258
259 if (enable_callstack) {
260 ___tracy_emit_memory_alloc_callstack(ptr, len, callstack_depth, 0);
261 } else {
262 ___tracy_emit_memory_alloc(ptr, len, 0);
263 }
264}
265
266inline fn allocNamed(ptr: [*]u8, len: usize, comptime name: [:0]const u8) void {
267 if (!enable) return;
268
269 if (enable_callstack) {
270 ___tracy_emit_memory_alloc_callstack_named(ptr, len, callstack_depth, 0, name.ptr);
271 } else {
272 ___tracy_emit_memory_alloc_named(ptr, len, 0, name.ptr);
273 }
274}
275
276inline fn free(ptr: [*]u8) void {
277 if (!enable) return;
278
279 if (enable_callstack) {
280 ___tracy_emit_memory_free_callstack(ptr, callstack_depth, 0);
281 } else {
282 ___tracy_emit_memory_free(ptr, 0);
283 }
284}
285
286inline fn freeNamed(ptr: [*]u8, comptime name: [:0]const u8) void {
287 if (!enable) return;
288
289 if (enable_callstack) {
290 ___tracy_emit_memory_free_callstack_named(ptr, callstack_depth, 0, name.ptr);
291 } else {
292 ___tracy_emit_memory_free_named(ptr, 0, name.ptr);
293 }
294}
295
296extern fn ___tracy_emit_zone_begin(
297 srcloc: *const ___tracy_source_location_data,
298 active: c_int,
299) ___tracy_c_zone_context;
300extern fn ___tracy_emit_zone_begin_callstack(
301 srcloc: *const ___tracy_source_location_data,
302 depth: c_int,
303 active: c_int,
304) ___tracy_c_zone_context;
305extern fn ___tracy_emit_zone_text(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
306extern fn ___tracy_emit_zone_name(ctx: ___tracy_c_zone_context, txt: [*]const u8, size: usize) void;
307extern fn ___tracy_emit_zone_color(ctx: ___tracy_c_zone_context, color: u32) void;
308extern fn ___tracy_emit_zone_value(ctx: ___tracy_c_zone_context, value: u64) void;
309extern fn ___tracy_emit_zone_end(ctx: ___tracy_c_zone_context) void;
310extern fn ___tracy_emit_memory_alloc(ptr: *const anyopaque, size: usize, secure: c_int) void;
311extern fn ___tracy_emit_memory_alloc_callstack(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int) void;
312extern fn ___tracy_emit_memory_free(ptr: *const anyopaque, secure: c_int) void;
313extern fn ___tracy_emit_memory_free_callstack(ptr: *const anyopaque, depth: c_int, secure: c_int) void;
314extern fn ___tracy_emit_memory_alloc_named(ptr: *const anyopaque, size: usize, secure: c_int, name: [*:0]const u8) void;
315extern fn ___tracy_emit_memory_alloc_callstack_named(ptr: *const anyopaque, size: usize, depth: c_int, secure: c_int, name: [*:0]const u8) void;
316extern fn ___tracy_emit_memory_free_named(ptr: *const anyopaque, secure: c_int, name: [*:0]const u8) void;
317extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth: c_int, secure: c_int, name: [*:0]const u8) void;
318extern fn ___tracy_emit_message(txt: [*]const u8, size: usize, callstack: c_int) void;
319extern fn ___tracy_emit_messageL(txt: [*:0]const u8, callstack: c_int) void;
320extern fn ___tracy_emit_messageC(txt: [*]const u8, size: usize, color: u32, callstack: c_int) void;
321extern fn ___tracy_emit_messageLC(txt: [*:0]const u8, color: u32, callstack: c_int) void;
322extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void;
323
324const ___tracy_source_location_data = extern struct {
325 name: ?[*:0]const u8,
326 function: [*:0]const u8,
327 file: [*:0]const u8,
328 line: u32,
329 color: u32,
330};