From 3225e9ebb195b1cc237c7b8d9de3d51c6863cb5e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 9 Aug 2026 15:39:28 -0700 Subject: [PATCH] macos: cache unified logging loggers per scope The logFn for macOS unified logging created and released an os_log_t logger on every single log call. Loggers are now cached per log scope for the process lifetime via an atomic pointer (a creation race wastes at most one create). Measured on macOS (Apple Silicon) with local timing instrumentation during app launch, the version-info logging block in global.init: before: 1070us-2629us after: 858us-1319us --- src/main_ghostty.zig | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/main_ghostty.zig b/src/main_ghostty.zig index cd2ef0c17..86e779899 100644 --- a/src/main_ghostty.zig +++ b/src/main_ghostty.zig @@ -140,11 +140,12 @@ fn logFn( .err => .fault, }; - // Initialize a logger. This is slow to do on every operation - // but we shouldn't be logging too much. - const logger = macos.os.Log.create(build_config.bundle_id, @tagName(scope)); - defer logger.release(); - logger.log(std.heap.c_allocator, mac_level, prefix ++ format, args); + macosLogger(scope).log( + std.heap.c_allocator, + mac_level, + prefix ++ format, + args, + ); } stderr: { @@ -166,6 +167,37 @@ fn logFn( } } +/// Returns the macOS unified logging logger for the given scope. The +/// logger is created once per scope and cached for the lifetime of the +/// process, because os_log object creation is slow (it shows up in +/// startup profiles when done per log call) and Apple's guidance is to +/// create loggers once and reuse them. +fn macosLogger(comptime scope: @TypeOf(.EnumLiteral)) *macos.os.Log { + const S = struct { + var cached: std.atomic.Value(?*macos.os.Log) = .init(null); + }; + + if (S.cached.load(.acquire)) |v| return v; + + // Create and attempt to store our logger. If we race with another + // thread then we use theirs and release ours. + const created = macos.os.Log.create( + build_config.bundle_id, + @tagName(scope), + ); + if (S.cached.cmpxchgStrong( + null, + created, + .acq_rel, + .acquire, + )) |existing| { + created.release(); + return existing.?; + } + + return created; +} + pub const std_options: std.Options = .{ // Our log level is always at least info in every build mode. //