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};