aboutsummaryrefslogtreecommitdiff
path: root/src/command/benchmark.zig
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-07-19 20:18:15 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2025-07-19 20:18:15 +0200
commitae10b7d764d9587ab92a682781f8479107e8dff0 (patch)
tree13e060f304ca1cac98ae1e71a2a6e27d9c5fb269 /src/command/benchmark.zig
parentd138a622dcc77302cc452c52946f6202b6a03f5e (diff)
add pex
Diffstat (limited to 'src/command/benchmark.zig')
-rw-r--r--src/command/benchmark.zig272
1 files changed, 156 insertions, 116 deletions
diff --git a/src/command/benchmark.zig b/src/command/benchmark.zig
index 98ec49f..bbb8cb7 100644
--- a/src/command/benchmark.zig
+++ b/src/command/benchmark.zig
@@ -2,149 +2,189 @@ const std = @import("std");
const root = @import("../main.zig");
const BenchmarkArgs = root.argument.BenchmarkArgs;
const recognizer = root.recognizer;
+const Pex = @import("../pex/root.zig");
fn write_result(
- writer: anytype,
- is_tty: bool,
- name: []const u8,
- index: usize,
- accepted: bool,
- elapsed: u64,
- throughput: f64,
+ writer: anytype,
+ is_tty: bool,
+ name: []const u8,
+ index: usize,
+ result: recognizer.Result,
+ elapsed: u64,
+ throughput: f64,
) !void {
- if (is_tty) {
- try writer.print("{s}[{}] {s}\x1b[0m ({}, {d:.2} tps)\n", .{
- name,
- index,
- if (accepted) "\x1b[32maccept"
- else "\x1b[31mreject",
- std.fmt.fmtDuration(elapsed),
- throughput,
- });
- } else {
- try writer.print("{s}[{}] {s} ({}, {d:.2} tps)\n", .{
- name,
- index,
- if (accepted) "accept"
- else "reject",
- std.fmt.fmtDuration(elapsed),
- throughput,
- });
- }
+ if (is_tty) {
+ try writer.print("{s}[{}] {s}\x1b[0m ({:.2}, {d:.2} tps, {})\n", .{
+ name,
+ index,
+ if (result.is_accepted) "\x1b[32maccept"
+ else "\x1b[31mreject",
+ std.fmt.fmtDuration(elapsed),
+ throughput,
+ result.info,
+ });
+ } else {
+ try writer.print("{s}[{}] {s} ({:.2}, {d:.2} tps, {})\n", .{
+ name,
+ index,
+ if (result.is_accepted) "accept"
+ else "reject",
+ std.fmt.fmtDuration(elapsed),
+ throughput,
+ result.info,
+ });
+ }
+}
+
+fn write_result_as_csv(
+ writer: anytype,
+ index: usize,
+ input_length: usize,
+ result: recognizer.Result,
+ elapsed: u64,
+ throughput: f64,
+) !void {
+ try writer.print("{},{},{d:.2},{d:.2},{:.2},{}\n", .{
+ index,
+ input_length,
+ elapsed,
+ throughput,
+ result.info.max_heap_size,
+ result.info.number_of_nodes,
+ });
}
fn write_summary(
- writer: anytype,
- is_tty: bool,
- total: usize,
- accepted: usize,
- total_time: u64,
- throughput: struct { f64, f64, f64 },
+ writer: anytype,
+ is_tty: bool,
+ total: usize,
+ accepted: usize,
+ total_time: u64,
+ throughput: struct { f64, f64, f64 },
) !void {
- const min, const max, const avg = throughput;
+ const min, const max, const avg = throughput;
- if (is_tty) {
- try writer.print("finished {} ({} \x1b[32maccepted\x1b[0m {d:.2} \x1b[31mrejected\x1b[0m)", .{
- total,
- accepted,
- total - accepted,
- });
- } else {
- try writer.print("finished {} ({} accepted {} rejected)", .{
- total,
- accepted,
- total - accepted,
- });
- }
+ if (is_tty) {
+ try writer.print("finished {} ({} \x1b[32maccepted\x1b[0m {} \x1b[31mrejected\x1b[0m)", .{
+ total,
+ accepted,
+ total - accepted,
+ });
+ } else {
+ try writer.print("finished {} ({} accepted {} rejected)", .{
+ total,
+ accepted,
+ total - accepted,
+ });
+ }
- try writer.print(" in {} (min: {d:.5} tps, max: {d:.2} tps, average: {d:.2} tps)\n", .{
- std.fmt.fmtDuration(total_time),
- min,
- max,
- avg,
- });
+ try writer.print(" in {} (min: {d:.5} tps, max: {d:.2} tps, average: {d:.2} tps)\n", .{
+ std.fmt.fmtDuration(total_time),
+ min,
+ max,
+ avg,
+ });
}
fn min_max_avg(values: []f64) struct { f64, f64, f64 } {
- var min: f64 = -1;
- var max: f64 = 0;
- var sum: f64 = 0;
+ var min: f64 = -1;
+ var max: f64 = 0;
+ var sum: f64 = 0;
- for (values) |value| {
- min = if (min < 0) value else @min(min, value);
- max = @max(max, value);
- sum += value;
- }
+ for (values) |value| {
+ min = if (min < 0) value else @min(min, value);
+ max = @max(max, value);
+ sum += value;
+ }
- return .{ min, max, sum / @as(f64, @floatFromInt(values.len)) };
+ return .{ min, max, sum / @as(f64, @floatFromInt(values.len)) };
}
pub fn benchmark(args: *BenchmarkArgs, allocator: std.mem.Allocator) !void {
- const stdout = std.io.getStdOut();
- const writer = stdout.writer();
+ const stdout = std.io.getStdOut();
+ const writer = stdout.writer();
+
+ if (args.csv) {
+ try writer.print("index,input length,duration [ns],throughput,max heap size [bytes],number of nodes\n", .{});
+ }
+
+ var bufreader = std.io.bufferedReader(args.input.file.reader());
+ var reader = bufreader.reader();
+ var index: usize = 0;
+ const stderr = std.io.getStdErr();
- var bufreader = std.io.bufferedReader(args.input.file.reader());
- var reader = bufreader.reader();
- var index: usize = 0;
- const stderr = std.io.getStdErr();
+ var throughputs = std.ArrayList(f64).init(allocator);
+ defer throughputs.deinit();
- var throughputs = std.ArrayList(f64).init(allocator);
- defer throughputs.deinit();
+ if (args.input.file.isTty()) {
+ try stderr.writeAll("> ");
+ }
- if (args.input.file.isTty()) {
- try stderr.writeAll("> ");
- }
+ var read_arena = std.heap.ArenaAllocator.init(allocator);
+ defer read_arena.deinit();
+ var number_of_accepted: usize = 0;
+ var total_time: u64 = 0;
+ var timer = try std.time.Timer.start();
- var read_arena = std.heap.ArenaAllocator.init(allocator);
- defer read_arena.deinit();
- var number_of_accepted: usize = 0;
- var total_time: u64 = 0;
- var timer = try std.time.Timer.start();
+ const pex: Pex = try .compile(&args.grammar, allocator);
- while (try reader.readUntilDelimiterOrEofAlloc(
- read_arena.allocator(),
- '\n',
- std.math.maxInt(usize)
- )) |buffer| {
+ while (try reader.readUntilDelimiterOrEofAlloc(
+ read_arena.allocator(),
+ '\n',
+ std.math.maxInt(usize)
+ )) |buffer| {
- const trimmed = std.mem.trim(u8, buffer, &std.ascii.whitespace);
+ const trimmed = std.mem.trim(u8, buffer, &std.ascii.whitespace);
- timer.reset();
- const accepted = try recognizer.check(
- &args.grammar,
- trimmed,
- allocator
- );
+ timer.reset();
+ const result = try recognizer.check(
+ &pex,
+ trimmed,
+ allocator
+ );
- const elapsed = timer.read();
- const throughput = @as(f64, @floatFromInt(trimmed.len)) / (@as(f64, @floatFromInt(elapsed)) / std.time.ns_per_s);
- try throughputs.append(throughput);
+ const elapsed = timer.read();
+ const throughput = @as(f64, @floatFromInt(trimmed.len)) / (@as(f64, @floatFromInt(elapsed)) / std.time.ns_per_s);
+ try throughputs.append(throughput);
- try write_result(
- writer,
- stdout.isTty(),
- args.input.name,
- index,
- accepted,
- elapsed,
- throughput,
- );
+ if (args.csv) {
+ try write_result_as_csv(
+ writer,
+ index,
+ trimmed.len,
+ result,
+ elapsed,
+ throughput,
+ );
+ } else {
+ try write_result(
+ writer,
+ stdout.isTty(),
+ args.input.name,
+ index,
+ result,
+ elapsed,
+ throughput,
+ );
+ }
- index += 1;
- number_of_accepted += @intFromBool(accepted);
- total_time += elapsed;
+ index += 1;
+ number_of_accepted += @intFromBool(result.is_accepted);
+ total_time += elapsed;
- if (args.input.file.isTty()) {
- try stderr.writeAll("> ");
- }
- }
+ if (args.input.file.isTty()) {
+ try stderr.writeAll("> ");
+ }
+ }
- try write_summary(
- writer,
- stdout.isTty(),
- index,
- number_of_accepted,
- total_time,
- min_max_avg(throughputs.items)
- );
+ if (!args.csv) {
+ try write_summary(
+ writer,
+ stdout.isTty(),
+ index,
+ number_of_accepted,
+ total_time,
+ min_max_avg(throughputs.items)
+ );
+ }
}