mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-22 19:56:08 +03:00
name threads and add more tracing
This commit is contained in:
@ -82,9 +82,6 @@ pub fn run(self: *App) !void {
|
|||||||
// Block for any glfw events.
|
// Block for any glfw events.
|
||||||
try glfw.waitEvents();
|
try glfw.waitEvents();
|
||||||
|
|
||||||
// Mark this so we're in a totally different "frame"
|
|
||||||
tracy.frameMark();
|
|
||||||
|
|
||||||
// If any windows are closing, destroy them
|
// If any windows are closing, destroy them
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < self.windows.items.len) {
|
while (i < self.windows.items.len) {
|
||||||
|
@ -408,6 +408,7 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
renderer.Thread.threadMain,
|
renderer.Thread.threadMain,
|
||||||
.{&self.renderer_thread},
|
.{&self.renderer_thread},
|
||||||
);
|
);
|
||||||
|
self.renderer_thr.setName("renderer") catch {};
|
||||||
|
|
||||||
// Start our IO thread
|
// Start our IO thread
|
||||||
self.io_thr = try std.Thread.spawn(
|
self.io_thr = try std.Thread.spawn(
|
||||||
@ -415,6 +416,7 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
termio.Thread.threadMain,
|
termio.Thread.threadMain,
|
||||||
.{&self.io_thread},
|
.{&self.io_thread},
|
||||||
);
|
);
|
||||||
|
self.io_thr.setName("io") catch {};
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ const glfw = @import("glfw");
|
|||||||
const libuv = @import("libuv");
|
const libuv = @import("libuv");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
||||||
|
const tracy = @import("tracy");
|
||||||
|
const trace = tracy.trace;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const log = std.log.scoped(.renderer_thread);
|
const log = std.log.scoped(.renderer_thread);
|
||||||
@ -183,6 +185,8 @@ pub fn threadMain(self: *Thread) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn threadMain_(self: *Thread) !void {
|
fn threadMain_(self: *Thread) !void {
|
||||||
|
tracy.setThreadName("renderer");
|
||||||
|
|
||||||
// Run our thread start/end callbacks. This is important because some
|
// Run our thread start/end callbacks. This is important because some
|
||||||
// renderers have to do per-thread setup. For example, OpenGL has to set
|
// renderers have to do per-thread setup. For example, OpenGL has to set
|
||||||
// some thread-local state since that is how it works.
|
// some thread-local state since that is how it works.
|
||||||
@ -202,6 +206,27 @@ fn threadMain_(self: *Thread) !void {
|
|||||||
self.cursor_h.setData(self);
|
self.cursor_h.setData(self);
|
||||||
try self.cursor_h.start(cursorTimerCallback, 600, 600);
|
try self.cursor_h.start(cursorTimerCallback, 600, 600);
|
||||||
|
|
||||||
|
// If we are using tracy, then we setup a prepare handle so that
|
||||||
|
// we can mark the frame.
|
||||||
|
var frame_h: libuv.Prepare = if (!tracy.enabled) undefined else frame_h: {
|
||||||
|
const alloc_ptr = self.loop.getData(Allocator).?;
|
||||||
|
const alloc = alloc_ptr.*;
|
||||||
|
const h = try libuv.Prepare.init(alloc, self.loop);
|
||||||
|
h.setData(self);
|
||||||
|
try h.start(prepFrameCallback);
|
||||||
|
|
||||||
|
break :frame_h h;
|
||||||
|
};
|
||||||
|
defer if (tracy.enabled) {
|
||||||
|
frame_h.close((struct {
|
||||||
|
fn callback(h: *libuv.Prepare) void {
|
||||||
|
const alloc_h = h.loop().getData(Allocator).?.*;
|
||||||
|
h.deinit(alloc_h);
|
||||||
|
}
|
||||||
|
}).callback);
|
||||||
|
_ = self.loop.run(.nowait) catch {};
|
||||||
|
};
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
log.debug("starting renderer thread", .{});
|
log.debug("starting renderer thread", .{});
|
||||||
defer log.debug("exiting renderer thread", .{});
|
defer log.debug("exiting renderer thread", .{});
|
||||||
@ -210,6 +235,9 @@ fn threadMain_(self: *Thread) !void {
|
|||||||
|
|
||||||
/// Drain the mailbox.
|
/// Drain the mailbox.
|
||||||
fn drainMailbox(self: *Thread) !void {
|
fn drainMailbox(self: *Thread) !void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
// This holds the mailbox lock for the duration of the drain. The
|
// This holds the mailbox lock for the duration of the drain. The
|
||||||
// expectation is that all our message handlers will be non-blocking
|
// expectation is that all our message handlers will be non-blocking
|
||||||
// ENOUGH to not mess up throughput on producers.
|
// ENOUGH to not mess up throughput on producers.
|
||||||
@ -252,6 +280,9 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wakeupCallback(h: *libuv.Async) void {
|
fn wakeupCallback(h: *libuv.Async) void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
const t = h.getData(Thread) orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
@ -273,6 +304,9 @@ fn wakeupCallback(h: *libuv.Async) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderCallback(h: *libuv.Timer) void {
|
fn renderCallback(h: *libuv.Timer) void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
const t = h.getData(Thread) orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
@ -284,6 +318,9 @@ fn renderCallback(h: *libuv.Timer) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cursorTimerCallback(h: *libuv.Timer) void {
|
fn cursorTimerCallback(h: *libuv.Timer) void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
const t = h.getData(Thread) orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
@ -294,6 +331,12 @@ fn cursorTimerCallback(h: *libuv.Timer) void {
|
|||||||
t.wakeup.send() catch {};
|
t.wakeup.send() catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepFrameCallback(h: *libuv.Prepare) void {
|
||||||
|
_ = h;
|
||||||
|
|
||||||
|
tracy.frameMark();
|
||||||
|
}
|
||||||
|
|
||||||
fn stopCallback(h: *libuv.Async) void {
|
fn stopCallback(h: *libuv.Async) void {
|
||||||
h.loop().stop();
|
h.loop().stop();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ const builtin = @import("builtin");
|
|||||||
const libuv = @import("libuv");
|
const libuv = @import("libuv");
|
||||||
const termio = @import("../termio.zig");
|
const termio = @import("../termio.zig");
|
||||||
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
||||||
|
const tracy = @import("tracy");
|
||||||
|
const trace = tracy.trace;
|
||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const log = std.log.scoped(.io_thread);
|
const log = std.log.scoped(.io_thread);
|
||||||
@ -133,6 +135,8 @@ pub fn threadMain(self: *Thread) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn threadMain_(self: *Thread) !void {
|
fn threadMain_(self: *Thread) !void {
|
||||||
|
tracy.setThreadName("pty io");
|
||||||
|
|
||||||
// Run our thread start/end callbacks. This allows the implementation
|
// Run our thread start/end callbacks. This allows the implementation
|
||||||
// to hook into the event loop as needed.
|
// to hook into the event loop as needed.
|
||||||
var data = try self.impl.threadEnter(self.loop);
|
var data = try self.impl.threadEnter(self.loop);
|
||||||
@ -151,6 +155,9 @@ fn threadMain_(self: *Thread) !void {
|
|||||||
|
|
||||||
/// Drain the mailbox, handling all the messages in our terminal implementation.
|
/// Drain the mailbox, handling all the messages in our terminal implementation.
|
||||||
fn drainMailbox(self: *Thread) !void {
|
fn drainMailbox(self: *Thread) !void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
// This holds the mailbox lock for the duration of the drain. The
|
// This holds the mailbox lock for the duration of the drain. The
|
||||||
// expectation is that all our message handlers will be non-blocking
|
// expectation is that all our message handlers will be non-blocking
|
||||||
// ENOUGH to not mess up throughput on producers.
|
// ENOUGH to not mess up throughput on producers.
|
||||||
@ -184,6 +191,9 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wakeupCallback(h: *libuv.Async) void {
|
fn wakeupCallback(h: *libuv.Async) void {
|
||||||
|
const zone = trace(@src());
|
||||||
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
const t = h.getData(Thread) orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("wakeup callback fired without data set", .{});
|
log.warn("wakeup callback fired without data set", .{});
|
||||||
|
Reference in New Issue
Block a user