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