Files
bun.sh/src/perf.zig
Jarred Sumner f3da1b80bc Use macOS signpost api for tracing (#14871)
Co-authored-by: Jarred-Sumner <Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Don Isaac <donald.isaac@gmail.com>
Co-authored-by: DonIsaac <DonIsaac@users.noreply.github.com>
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-03-31 04:13:11 -07:00

161 lines
4.4 KiB
Zig

const bun = @import("root").bun;
const std = @import("std");
pub const Ctx = union(enum) {
disabled: Disabled,
enabled: switch (bun.Environment.os) {
.mac => Darwin,
.linux => Linux,
else => Disabled,
},
pub const Disabled = struct {
pub inline fn end(_: *const @This()) void {}
};
pub fn end(this: *const @This()) void {
switch (this.*) {
inline else => |*ctx| ctx.end(),
}
}
};
var is_enabled_once = std.once(isEnabledOnce);
var is_enabled = std.atomic.Value(bool).init(false);
fn isEnabledOnMacOSOnce() void {
if (bun.getenvZ("DYLD_ROOT_PATH") != null or bun.getRuntimeFeatureFlag("BUN_INSTRUMENTS")) {
is_enabled.store(true, .seq_cst);
}
}
fn isEnabledOnLinuxOnce() void {
if (bun.getRuntimeFeatureFlag("BUN_TRACE")) {
is_enabled.store(true, .seq_cst);
}
}
fn isEnabledOnce() void {
if (comptime bun.Environment.isMac) {
isEnabledOnMacOSOnce();
if (Darwin.get() == null) {
is_enabled.store(false, .seq_cst);
}
} else if (comptime bun.Environment.isLinux) {
isEnabledOnLinuxOnce();
if (!Linux.isSupported()) {
is_enabled.store(false, .seq_cst);
}
}
}
pub fn isEnabled() bool {
is_enabled_once.call();
return is_enabled.load(.seq_cst);
}
const PerfEvent = @import("./generated_perf_trace_events.zig").PerfEvent;
/// Trace an event using the system profiler (Instruments).
///
/// When instruments is not connected, this is a no-op.
///
/// When adding a new event, you must run `scripts/generate-perf-trace-events.sh` to update the list of trace events.
///
/// Tip: Make sure you write bun.perf.trace() with a string literal exactly instead of passing a variable.
///
/// It has to be compile-time known this way because they need to become string literals in C.
pub fn trace(comptime name: [:0]const u8) Ctx {
comptime {
if (!@hasField(PerfEvent, name)) {
@compileError(std.fmt.comptimePrint(
\\"{s}" is missing from generated_perf_trace_events.zig
\\
\\Please run this command in your terminal and commit the result:
\\
\\ bash scripts/generate-perf-trace-events.sh
\\
\\Tip: Make sure you write bun.perf.trace as a string literal exactly instead of passing a variable.
,
.{
name,
},
));
}
}
if (!isEnabled()) {
@branchHint(.likely);
return .{ .disabled = .{} };
}
if (comptime bun.Environment.isMac) {
return .{ .enabled = Darwin.init(@intFromEnum(@field(PerfEvent, name))) };
} else if (comptime bun.Environment.isLinux) {
return .{ .enabled = Linux.init(@field(PerfEvent, name)) };
}
return .{ .disabled = .{} };
}
pub const Darwin = struct {
const OSLog = bun.C.OSLog;
interval: OSLog.Signpost.Interval,
pub fn init(comptime name: i32) @This() {
return .{
.interval = os_log.?.signpost(name).interval(.PointsOfInterest),
};
}
pub fn end(this: *const @This()) void {
this.interval.end();
}
var os_log: ?*OSLog = null;
var os_log_once = std.once(getOnce);
fn getOnce() void {
os_log = OSLog.init();
}
pub fn get() ?*OSLog {
os_log_once.call();
return os_log;
}
};
pub const Linux = struct {
start_time: u64,
event: PerfEvent,
var is_initialized = std.atomic.Value(bool).init(false);
var init_once = std.once(initOnce);
extern "c" fn Bun__linux_trace_init() c_int;
extern "c" fn Bun__linux_trace_close() void;
extern "c" fn Bun__linux_trace_emit(event_name: [*:0]const u8, duration_ns: i64) c_int;
fn initOnce() void {
const result = Bun__linux_trace_init();
is_initialized.store(result != 0, .monotonic);
}
pub fn isSupported() bool {
init_once.call();
return is_initialized.load(.monotonic);
}
pub fn init(event: PerfEvent) @This() {
return .{
.start_time = bun.timespec.now().ns(),
.event = event,
};
}
pub fn end(this: *const @This()) void {
if (!isSupported()) return;
const duration = bun.timespec.now().ns() -| this.start_time;
_ = Bun__linux_trace_emit(@tagName(this.event).ptr, @intCast(duration));
}
};