mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-18 09:46:07 +03:00
macos: add signpost API
This commit is contained in:
@ -18,15 +18,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
|
||||||
defer flags.deinit();
|
|
||||||
lib.addCSourceFile(.{
|
lib.addCSourceFile(.{
|
||||||
.file = b.path("os/zig_log.c"),
|
.file = b.path("os/zig_macos.c"),
|
||||||
.flags = flags.items,
|
.flags = &.{"-std=c99"},
|
||||||
});
|
});
|
||||||
lib.addCSourceFile(.{
|
lib.addCSourceFile(.{
|
||||||
.file = b.path("text/ext.c"),
|
.file = b.path("text/ext.c"),
|
||||||
.flags = flags.items,
|
|
||||||
});
|
});
|
||||||
lib.linkFramework("CoreFoundation");
|
lib.linkFramework("CoreFoundation");
|
||||||
lib.linkFramework("CoreGraphics");
|
lib.linkFramework("CoreGraphics");
|
||||||
|
@ -23,6 +23,7 @@ pub const c = @cImport({
|
|||||||
@cInclude("IOSurface/IOSurfaceRef.h");
|
@cInclude("IOSurface/IOSurfaceRef.h");
|
||||||
@cInclude("dispatch/dispatch.h");
|
@cInclude("dispatch/dispatch.h");
|
||||||
@cInclude("os/log.h");
|
@cInclude("os/log.h");
|
||||||
|
@cInclude("os/signpost.h");
|
||||||
|
|
||||||
if (builtin.os.tag == .macos) {
|
if (builtin.os.tag == .macos) {
|
||||||
@cInclude("Carbon/Carbon.h");
|
@cInclude("Carbon/Carbon.h");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const log = @import("os/log.zig");
|
const log = @import("os/log.zig");
|
||||||
|
|
||||||
pub const c = @import("os/c.zig");
|
pub const c = @import("os/c.zig");
|
||||||
|
pub const signpost = @import("os/signpost.zig");
|
||||||
pub const Log = log.Log;
|
pub const Log = log.Log;
|
||||||
pub const LogType = log.LogType;
|
pub const LogType = log.LogType;
|
||||||
|
|
||||||
|
161
pkg/macos/os/signpost.zig
Normal file
161
pkg/macos/os/signpost.zig
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const c = @import("c.zig").c;
|
||||||
|
const logpkg = @import("log.zig");
|
||||||
|
const Log = logpkg.Log;
|
||||||
|
|
||||||
|
/// Checks whether signpost logging is enabled for the given log handle.
|
||||||
|
/// Returns true if signposts will be recorded for this log, false otherwise.
|
||||||
|
/// This can be used to avoid expensive operations when signpost logging is disabled.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_enabled?language=objc
|
||||||
|
pub fn enabled(log: *Log) bool {
|
||||||
|
return c.os_signpost_enabled(@ptrCast(log));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Emits a signpost event - a single point in time marker.
|
||||||
|
/// Events are useful for marking when specific actions occur, such as
|
||||||
|
/// user interactions, state changes, or other discrete occurrences.
|
||||||
|
/// The event will appear as a vertical line in Instruments.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_event_emit?language=objc
|
||||||
|
pub fn emitEvent(
|
||||||
|
log: *Log,
|
||||||
|
id: Id,
|
||||||
|
comptime name: [:0]const u8,
|
||||||
|
) void {
|
||||||
|
emitWithName(log, id, .event, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the beginning of a time interval.
|
||||||
|
/// Use this with intervalEnd to measure the duration of operations.
|
||||||
|
/// The same ID must be used for both the begin and end calls.
|
||||||
|
/// Intervals appear as horizontal bars in Instruments timeline.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_interval_begin?language=objc
|
||||||
|
pub fn intervalBegin(log: *Log, id: Id, comptime name: [:0]const u8) void {
|
||||||
|
emitWithName(log, id, .interval_begin, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks the end of a time interval.
|
||||||
|
/// Must be paired with a prior intervalBegin call using the same ID.
|
||||||
|
/// The name should match the name used in intervalBegin.
|
||||||
|
/// Instruments will calculate and display the duration between begin and end.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_interval_end?language=objc
|
||||||
|
pub fn intervalEnd(log: *Log, id: Id, comptime name: [:0]const u8) void {
|
||||||
|
emitWithName(log, id, .interval_end, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern var __dso_handle: usize;
|
||||||
|
|
||||||
|
/// The internal function to emit a signpost with a specific name.
|
||||||
|
fn emitWithName(
|
||||||
|
log: *Log,
|
||||||
|
id: Id,
|
||||||
|
typ: Type,
|
||||||
|
comptime name: [:0]const u8,
|
||||||
|
) void {
|
||||||
|
var buf: [64]u8 = @splat(0);
|
||||||
|
c._os_signpost_emit_with_name_impl(
|
||||||
|
&__dso_handle,
|
||||||
|
@ptrCast(log),
|
||||||
|
@intFromEnum(typ),
|
||||||
|
@intFromEnum(id),
|
||||||
|
name.ptr,
|
||||||
|
null,
|
||||||
|
&buf,
|
||||||
|
buf.len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_t?language=objc
|
||||||
|
pub const Id = enum(u64) {
|
||||||
|
null = 0, // OS_SIGNPOST_ID_NULL
|
||||||
|
invalid = 0xFFFFFFFFFFFFFFFF, // OS_SIGNPOST_ID_INVALID
|
||||||
|
exclusive = 0xEEEEB0B5B2B2EEEE, // OS_SIGNPOST_ID_EXCLUSIVE
|
||||||
|
_,
|
||||||
|
|
||||||
|
/// Generates a new signpost ID for use with signpost operations.
|
||||||
|
/// The ID is unique for the given log handle and can be used to track
|
||||||
|
/// asynchronous operations or mark specific points of interest in the code.
|
||||||
|
/// Returns a unique signpost ID that can be used with os_signpost functions.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_generate?language=objc
|
||||||
|
pub fn generate(log: *Log) Id {
|
||||||
|
return @enumFromInt(c.os_signpost_id_generate(@ptrCast(log)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a signpost ID based on a pointer value.
|
||||||
|
/// This is useful for tracking operations associated with a specific object
|
||||||
|
/// or memory location. The same pointer will always generate the same ID
|
||||||
|
/// for a given log handle, allowing correlation of signpost events.
|
||||||
|
/// Pass null to get the null signpost ID.
|
||||||
|
///
|
||||||
|
/// https://developer.apple.com/documentation/os/os_signpost_id_for_pointer?language=objc
|
||||||
|
pub fn forPointer(log: *Log, ptr: ?*anyopaque) Id {
|
||||||
|
return @enumFromInt(c.os_signpost_id_make_with_pointer(
|
||||||
|
@ptrCast(log),
|
||||||
|
@ptrCast(ptr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "generate ID" {
|
||||||
|
// We can't really test the return value because it may return null
|
||||||
|
// if signposts are disabled.
|
||||||
|
const id: Id = .generate(Log.create("com.mitchellh.ghostty", "test"));
|
||||||
|
try std.testing.expect(id != .invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "generate ID for pointer" {
|
||||||
|
var foo: usize = 0x1234;
|
||||||
|
const id: Id = .forPointer(Log.create("com.mitchellh.ghostty", "test"), &foo);
|
||||||
|
try std.testing.expect(id != .null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// https://developer.apple.com/documentation/os/ossignposttype?language=objc
|
||||||
|
pub const Type = enum(u8) {
|
||||||
|
event = 0, // OS_SIGNPOST_EVENT
|
||||||
|
interval_begin = 1, // OS_SIGNPOST_INTERVAL_BEGIN
|
||||||
|
interval_end = 2, // OS_SIGNPOST_INTERVAL_END
|
||||||
|
|
||||||
|
pub const mask: u8 = 0x03; // OS_SIGNPOST_TYPE_MASK
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Special os_log category values that surface in Instruments and other
|
||||||
|
/// tooling.
|
||||||
|
pub const Category = struct {
|
||||||
|
/// Points of Interest appear as a dedicated track in Instruments.
|
||||||
|
/// Use this for high-level application events that help understand
|
||||||
|
/// the flow of your application.
|
||||||
|
pub const points_of_interest: [:0]const u8 = "PointsOfInterest";
|
||||||
|
|
||||||
|
/// Dynamic Tracing category enables runtime-configurable logging.
|
||||||
|
/// Signposts in this category can be enabled/disabled dynamically
|
||||||
|
/// without recompiling.
|
||||||
|
pub const dynamic_tracing: [:0]const u8 = "DynamicTracking";
|
||||||
|
|
||||||
|
/// Dynamic Stack Tracing category captures call stacks at signpost
|
||||||
|
/// events. This provides deeper debugging information but has higher
|
||||||
|
/// performance overhead.
|
||||||
|
pub const dynamic_stack_tracing: [:0]const u8 = "DynamicStackTracking";
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
test enabled {
|
||||||
|
_ = enabled(Log.create("com.mitchellh.ghostty", "test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "intervals" {
|
||||||
|
const log = Log.create("com.mitchellh.ghostty", "test");
|
||||||
|
defer log.release();
|
||||||
|
|
||||||
|
// Test that we can begin and end an interval
|
||||||
|
const id = Id.generate(log);
|
||||||
|
intervalBegin(log, id, "Test Interval");
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <os/log.h>
|
#include <os/log.h>
|
||||||
|
#include <os/signpost.h>
|
||||||
|
|
||||||
// A wrapper so we can use the os_log_with_type macro.
|
// A wrapper so we can use the os_log_with_type macro.
|
||||||
void zig_os_log_with_type(
|
void zig_os_log_with_type(
|
Reference in New Issue
Block a user