Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions packages/core/scripts/gate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,19 @@ try {
}

const zig = (args) => execFileSync("zig", args, { cwd: work, stdio: "inherit" });
const executableName = (name) => process.platform === "win32" ? `${name}.exe` : name;
const executable = (name) => path.join(work, executableName(name));

// 3. Build ReleaseSafe (the shipping mode: index checks stay on).
zig(["build-lib", "-OReleaseSafe", "-femit-bin=libinbox.a", "shim.zig"]);
zig(["build-lib", "-OReleaseSafe", "-femit-bin=libinbox.a", "shim.zig", "-lc"]);
zig([
"build-exe", "-OReleaseSafe", "-femit-bin=bench_safe",
"build-exe", "-OReleaseSafe", `-femit-bin=${executableName("bench_safe")}`,
"--dep", "impl", "-Mroot=bench.zig", "-Mimpl=impl.zig", "libinbox.a", "-lc",
]);
log("built ReleaseSafe");

// 4. run1k digest gate.
execFileSync(path.join(work, "bench_safe"), ["run1k", "run1k.txt"], { cwd: work, stdio: "inherit" });
execFileSync(executable("bench_safe"), ["run1k", "run1k.txt"], { cwd: work, stdio: "inherit" });
const digest = createHash("md5").update(fs.readFileSync(path.join(work, "run1k.txt"))).digest("hex");
if (digest !== ORACLE_RUN1K_MD5) {
console.error(`[gate] FAIL run1k digest ${digest} != oracle ${ORACLE_RUN1K_MD5}`);
Expand All @@ -70,14 +72,14 @@ try {
// 5. Perf band.
if (!skipBench) {
log("bench10k (ReleaseSafe):");
execFileSync(path.join(work, "bench_safe"), ["bench10k"], { cwd: work, stdio: "inherit" });
zig(["build-lib", "-OReleaseFast", "-femit-bin=libinbox_fast.a", "shim.zig"]);
execFileSync(executable("bench_safe"), ["bench10k"], { cwd: work, stdio: "inherit" });
zig(["build-lib", "-OReleaseFast", "-femit-bin=libinbox_fast.a", "shim.zig", "-lc"]);
zig([
"build-exe", "-OReleaseFast", "-femit-bin=bench_fast",
"build-exe", "-OReleaseFast", `-femit-bin=${executableName("bench_fast")}`,
"--dep", "impl", "-Mroot=bench.zig", "-Mimpl=impl.zig", "libinbox_fast.a", "-lc",
]);
log("bench10k (ReleaseFast):");
execFileSync(path.join(work, "bench_fast"), ["bench10k"], { cwd: work, stdio: "inherit" });
execFileSync(executable("bench_fast"), ["bench10k"], { cwd: work, stdio: "inherit" });
}

log("PASS");
Expand Down
27 changes: 13 additions & 14 deletions packages/core/test/fixtures/bench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,23 @@ fn run1k(alloc: std.mem.Allocator, io: std.Io, out_path: []const u8) !void {
std.debug.print("run1k wrote {s} ({d} bytes, {d} effect bytes)\n", .{ out_path, out.items.len, eff_len });
}

// Raw monotonic nanoseconds (darwin). ~41ns granularity on Apple Silicon.
extern "c" fn clock_gettime_nsec_np(clock_id: c_int) u64;
const CLOCK_UPTIME_RAW: c_int = 8;
inline fn nowNs() u64 {
return clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
// Monotonic awake-time nanoseconds. This maps to CLOCK_UPTIME_RAW on macOS
// while retaining the same benchmark contract on other supported hosts.
inline fn nowNs(io: std.Io) u64 {
return @intCast(@max(std.Io.Timestamp.now(io, .awake).nanoseconds, 0));
Comment thread
vercel[bot] marked this conversation as resolved.
}

fn bench10k(alloc: std.mem.Allocator) !void {
fn bench10k(alloc: std.mem.Allocator, io: std.Io) !void {
impl.reset();
var rng = SplitMix{ .state = 0xdead_beef_cafe_f00d };
const iters = 10_000;
const samples = try alloc.alloc(u64, iters);

const bench_start = nowNs();
const bench_start = nowNs(io);
for (0..iters) |i| {
// Keystroke-shaped mix: mostly single-char inserts.
const roll = rng.below(1000);
const t0 = nowNs();
const t0 = nowNs(io);
if (roll < 700) {
impl.pushText(@floatFromInt(0x61 + rng.below(26)));
_ = impl.dispatch(4, 0, 0, 0, 0, 0);
Expand All @@ -159,9 +158,9 @@ fn bench10k(alloc: std.mem.Allocator) !void {
} else {
_ = impl.dispatch(3, 0, 0, 0, 0, 0); // clear_done
}
samples[i] = nowNs() - t0;
samples[i] = nowNs(io) - t0;
}
const wall_total = nowNs() - bench_start;
const wall_total = nowNs(io) - bench_start;

std.mem.sort(u64, samples, {}, std.sort.asc(u64));
var total: u64 = 0;
Expand Down Expand Up @@ -190,15 +189,15 @@ pub fn main(init: std.process.Init) !void {
const alloc = init.arena.allocator();
impl.init();

const argv = init.minimal.args.vector;
const mode: []const u8 = if (argv.len > 1) std.mem.span(argv[1]) else "smoke";
const args = try init.minimal.args.toSlice(alloc);
const mode: []const u8 = if (args.len > 1) args[1] else "smoke";

if (std.mem.eql(u8, mode, "smoke")) {
try smoke(alloc);
} else if (std.mem.eql(u8, mode, "run1k")) {
try run1k(alloc, init.io, std.mem.span(argv[2]));
try run1k(alloc, init.io, args[2]);
} else if (std.mem.eql(u8, mode, "bench10k")) {
try bench10k(alloc);
try bench10k(alloc, init.io);
} else {
std.debug.print("unknown mode {s}\n", .{mode});
}
Expand Down