authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-01-13 19:10:45-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-09 10:47:21-05:00
log7e8ee985e20f34ba6afb815a7cded443aca297d3
treedf089878f2f2360f26eae2cd847aa17f2d6fdb85
parentf2cbc1912b9c58c2a20b9f32fb60b7793f5e4820

tracy: add fiber integration


4 files changed, 69 insertions(+), 3 deletions(-)

build.zig+12-2
...@@ -370,10 +370,20 @@ pub fn build(b: *std.Build) !void {...@@ -370,10 +370,20 @@ pub fn build(b: *std.Build) !void {
370 &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" },370 &[_][]const u8{ tracy_path, "public", "TracyClient.cpp" },
371 );371 );
372372
373 const tracy_c_flags: []const []const u8 = &.{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };373 const tracy_c_flags: []const []const u8 = &.{
374 "-DTRACY_ENABLE=1",
375 "-fno-sanitize=undefined",
376 "-DTRACY_FIBERS",
377 };
374378
375 exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path });379 exe.root_module.addIncludePath(.{ .cwd_relative = tracy_path });
376 exe.root_module.addCSourceFile(.{ .file = .{ .cwd_relative = client_cpp }, .flags = tracy_c_flags });380 exe.root_module.addCSourceFile(.{
381 .file = .{ .cwd_relative = client_cpp },
382 .flags = tracy_c_flags[0..switch (io_mode) {
383 .threaded => 2,
384 .evented => 3,
385 }],
386 });
377 exe.root_module.link_libc = true;387 exe.root_module.link_libc = true;
378 exe.root_module.link_libcpp = true;388 exe.root_module.link_libcpp = true;
379389
lib/std/Io/IoUring.zig+44
...@@ -44,6 +44,14 @@ const timestampFromPosix = Io.Threaded.timestampFromPosix;...@@ -44,6 +44,14 @@ const timestampFromPosix = Io.Threaded.timestampFromPosix;
44const unexpectedErrno = std.posix.unexpectedErrno;44const unexpectedErrno = std.posix.unexpectedErrno;
45const winsize = std.posix.winsize;45const winsize = std.posix.winsize;
4646
47const tracy = if (@hasDecl(@import("root"), "tracy")) @import("root").tracy else struct {
48 const enable = false;
49 inline fn fiberEnter(fiber: [*:0]const u8) void {
50 _ = fiber;
51 }
52 inline fn fiberLeave() void {}
53};
54
47backing_allocator_needs_mutex: bool,55backing_allocator_needs_mutex: bool,
48backing_allocator_mutex: Io.Mutex,56backing_allocator_mutex: Io.Mutex,
49/// Does not need to be thread-safe if not used elsewhere.57/// Does not need to be thread-safe if not used elsewhere.
...@@ -90,6 +98,7 @@ const Thread = struct {...@@ -90,6 +98,7 @@ const Thread = struct {
90 io_uring: IoUring,98 io_uring: IoUring,
91 idle_search_index: u32,99 idle_search_index: u32,
92 steal_ready_search_index: u32,100 steal_ready_search_index: u32,
101 name_arena: if (tracy.enable) std.heap.ArenaAllocator.State else struct {},
93 csprng: Csprng,102 csprng: Csprng,
94103
95 threadlocal var self: ?*Thread = null;104 threadlocal var self: ?*Thread = null;
...@@ -138,6 +147,9 @@ const Fiber = struct {...@@ -138,6 +147,9 @@ const Fiber = struct {
138 },147 },
139 cancel_status: CancelStatus,148 cancel_status: CancelStatus,
140 cancel_protection: CancelProtection,149 cancel_protection: CancelProtection,
150 name: if (tracy.enable) [*:0]const u8 else void,
151
152 var next_name: u64 = 0;
141153
142 const CancelStatus = packed struct(u32) {154 const CancelStatus = packed struct(u32) {
143 requested: bool,155 requested: bool,
...@@ -772,6 +784,7 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v...@@ -772,6 +784,7 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v
772 .status = .{ .queue_next = null },784 .status = .{ .queue_next = null },
773 .cancel_status = .unrequested,785 .cancel_status = .unrequested,
774 .cancel_protection = .unblocked,786 .cancel_protection = .unblocked,
787 .name = if (tracy.enable) "main task",
775 };788 };
776 const main_thread = &ev.threads.allocated[0];789 const main_thread = &ev.threads.allocated[0];
777 Thread.self = main_thread;790 Thread.self = main_thread;
...@@ -802,11 +815,13 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v...@@ -802,11 +815,13 @@ pub fn init(ev: *Evented, backing_allocator: Allocator, options: InitOptions) !v
802 ),815 ),
803 .idle_search_index = 1,816 .idle_search_index = 1,
804 .steal_ready_search_index = 1,817 .steal_ready_search_index = 1,
818 .name_arena = .{},
805 .csprng = .uninitialized,819 .csprng = .uninitialized,
806 };820 };
807 errdefer main_thread.io_uring.deinit();821 errdefer main_thread.io_uring.deinit();
808 log.debug("created main idle {*}", .{&main_thread.idle_context});822 log.debug("created main idle {*}", .{&main_thread.idle_context});
809 log.debug("created main {*}", .{main_fiber});823 log.debug("created main {*}", .{main_fiber});
824 if (tracy.enable) tracy.fiberEnter(main_fiber.name);
810}825}
811826
812pub fn deinit(ev: *Evented) void {827pub fn deinit(ev: *Evented) void {
...@@ -958,6 +973,7 @@ fn schedule(ev: *Evented, thread: *Thread, ready_queue: Fiber.Queue) bool {...@@ -958,6 +973,7 @@ fn schedule(ev: *Evented, thread: *Thread, ready_queue: Fiber.Queue) bool {
958 },973 },
959 .idle_search_index = 0,974 .idle_search_index = 0,
960 .steal_ready_search_index = 0,975 .steal_ready_search_index = 0,
976 .name_arena = .{},
961 .csprng = .uninitialized,977 .csprng = .uninitialized,
962 };978 };
963 new_thread.thread = std.Thread.spawn(.{979 new_thread.thread = std.Thread.spawn(.{
...@@ -1160,6 +1176,12 @@ const SwitchMessage = struct {...@@ -1160,6 +1176,12 @@ const SwitchMessage = struct {
1160 fn handle(message: *const SwitchMessage, ev: *Evented) void {1176 fn handle(message: *const SwitchMessage, ev: *Evented) void {
1161 const thread: *Thread = .current();1177 const thread: *Thread = .current();
1162 thread.current_context = message.contexts.ready;1178 thread.current_context = message.contexts.ready;
1179 if (tracy.enable) {
1180 if (message.contexts.ready != &thread.idle_context) {
1181 const fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.ready));
1182 tracy.fiberEnter(fiber.name);
1183 } else tracy.fiberLeave();
1184 }
1163 switch (message.pending_task) {1185 switch (message.pending_task) {
1164 .nothing => {},1186 .nothing => {},
1165 .reschedule => if (message.contexts.prev != &thread.idle_context) {1187 .reschedule => if (message.contexts.prev != &thread.idle_context) {
...@@ -1543,6 +1565,17 @@ fn concurrent(...@@ -1543,6 +1565,17 @@ fn concurrent(
1543 .status = .{ .queue_next = null },1565 .status = .{ .queue_next = null },
1544 .cancel_status = .unrequested,1566 .cancel_status = .unrequested,
1545 .cancel_protection = .unblocked,1567 .cancel_protection = .unblocked,
1568 .name = if (tracy.enable) name: {
1569 const thread: *Thread = .current();
1570 var name_arena = thread.name_arena.promote(std.heap.page_allocator);
1571 defer thread.name_arena = name_arena.state;
1572 break :name std.fmt.allocPrintSentinel(
1573 name_arena.allocator(),
1574 "task {d}",
1575 .{@atomicRmw(u64, &Fiber.next_name, .Add, 1, .monotonic)},
1576 0,
1577 ) catch return error.ConcurrencyUnavailable;
1578 },
1546 };1579 };
1547 closure.* = .{1580 closure.* = .{
1548 .ev = ev,1581 .ev = ev,
...@@ -1920,6 +1953,17 @@ fn groupConcurrent(...@@ -1920,6 +1953,17 @@ fn groupConcurrent(
1920 .status = .{ .queue_next = null },1953 .status = .{ .queue_next = null },
1921 .cancel_status = .unrequested,1954 .cancel_status = .unrequested,
1922 .cancel_protection = .unblocked,1955 .cancel_protection = .unblocked,
1956 .name = if (tracy.enable) name: {
1957 const thread: *Thread = .current();
1958 var name_arena = thread.name_arena.promote(std.heap.page_allocator);
1959 defer thread.name_arena = name_arena.state;
1960 break :name std.fmt.allocPrintSentinel(
1961 name_arena.allocator(),
1962 "group task {d}",
1963 .{@atomicRmw(u64, &Fiber.next_name, .Add, 1, .monotonic)},
1964 0,
1965 ) catch return error.ConcurrencyUnavailable;
1966 },
1923 };1967 };
1924 closure.* = .{1968 closure.* = .{
1925 .ev = ev,1969 .ev = ev,
src/main.zig+1-1
...@@ -21,7 +21,7 @@ const AstGen = std.zig.AstGen;...@@ -21,7 +21,7 @@ const AstGen = std.zig.AstGen;
21const ZonGen = std.zig.ZonGen;21const ZonGen = std.zig.ZonGen;
22const Server = std.zig.Server;22const Server = std.zig.Server;
2323
24const tracy = @import("tracy.zig");24pub const tracy = @import("tracy.zig");
25const Compilation = @import("Compilation.zig");25const Compilation = @import("Compilation.zig");
26const link = @import("link.zig");26const link = @import("link.zig");
27const Package = @import("Package.zig");27const Package = @import("Package.zig");
src/tracy.zig+12
...@@ -98,6 +98,16 @@ pub inline fn traceNamed(comptime src: std.builtin.SourceLocation, comptime name...@@ -98,6 +98,16 @@ pub inline fn traceNamed(comptime src: std.builtin.SourceLocation, comptime name
98 }98 }
99}99}
100100
101pub inline fn fiberEnter(fiber: [*:0]const u8) void {
102 if (!enable) return;
103 ___tracy_fiber_enter(fiber);
104}
105
106pub inline fn fiberLeave() void {
107 if (!enable) return;
108 ___tracy_fiber_leave();
109}
110
101pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) {111pub fn tracyAllocator(allocator: std.mem.Allocator) TracyAllocator(null) {
102 return TracyAllocator(null).init(allocator);112 return TracyAllocator(null).init(allocator);
103}113}
...@@ -318,6 +328,8 @@ extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth...@@ -318,6 +328,8 @@ extern fn ___tracy_emit_memory_free_callstack_named(ptr: *const anyopaque, depth
318extern fn ___tracy_emit_logString(severity: MessageSeverity, color: i32, callstack_depth: i32, size: usize, txt: [*]const u8) void;328extern fn ___tracy_emit_logString(severity: MessageSeverity, color: i32, callstack_depth: i32, size: usize, txt: [*]const u8) void;
319extern fn ___tracy_emit_logStringL(severity: MessageSeverity, color: i32, callstack_depth: i32, txt: [*:0]const u8) void;329extern fn ___tracy_emit_logStringL(severity: MessageSeverity, color: i32, callstack_depth: i32, txt: [*:0]const u8) void;
320extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void;330extern fn ___tracy_emit_frame_mark(name: ?[*:0]const u8) void;
331extern fn ___tracy_fiber_enter(fiber: [*:0]const u8) void;
332extern fn ___tracy_fiber_leave() void;
321333
322const ___tracy_source_location_data = extern struct {334const ___tracy_source_location_data = extern struct {
323 name: ?[*:0]const u8,335 name: ?[*:0]const u8,