Skip to content

Commit

Permalink
Parameterised benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
bens committed Mar 19, 2024
1 parent 83bb32d commit 5c1c39b
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn setupExamples(b: *std.Build, target: std.zig.CrossTarget, optimize: std.built
const example_names = [_][]const u8{
"basic",
"bubble_sort",
"parameterised",
"sleep",
};

Expand Down
30 changes: 30 additions & 0 deletions examples/parameterised.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const std = @import("std");
const zbench = @import("zbench");
const test_allocator = std.testing.allocator;

const MyBenchmark = struct {
loops: usize,

fn init(loops: usize) MyBenchmark {
return .{ .loops = loops };
}

pub fn run(self: MyBenchmark, _: std.mem.Allocator) void {
var result: usize = 0;
for (0..self.loops) |i| result += i * i;
}
};

test "bench test parameterised" {
const stdout = std.io.getStdOut().writer();
var bench = zbench.Benchmark.init(test_allocator, .{});
defer bench.deinit();

try bench.addParam("My Benchmark 1", &MyBenchmark.init(100_000), .{});
try bench.addParam("My Benchmark 2", &MyBenchmark.init(200_000), .{});

const results = try bench.run();
defer results.deinit();
try stdout.writeAll("\n");
try results.prettyPrint(stdout, true);
}
48 changes: 45 additions & 3 deletions zbench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,22 @@ pub const Config = struct {
/// A benchmark definition.
const Definition = struct {
name: []const u8,
func: BenchFunc,
config: Config,
defn: union(enum) {
simple: BenchFunc,
parameterised: struct {
func: ParameterisedFunc,
context: *const anyopaque,
},
},
};

/// A function pointer type that represents a benchmark function.
pub const BenchFunc = *const fn (std.mem.Allocator) void;

/// A function pointer type that represents a parameterised benchmark function.
pub const ParameterisedFunc = *const fn (*const anyopaque, std.mem.Allocator) void;

/// Benchmark manager, add your benchmark functions and run measure them.
pub const Benchmark = struct {
allocator: std.mem.Allocator,
Expand All @@ -84,7 +93,37 @@ pub const Benchmark = struct {
) !void {
try self.benchmarks.append(self.allocator, Definition{
.name = name,
.func = func,
.defn = .{ .simple = func },
.config = optional(Config, config, self.common_config),
});
}

/// Add a benchmark function to be timed with `run()`.
pub fn addParam(
self: *Benchmark,
name: []const u8,
benchmark: anytype,
config: Optional(Config),
) !void {
// Check the benchmark parameter is the proper type.
const T: type = switch (@typeInfo(@TypeOf(benchmark))) {
.Pointer => |ptr| if (ptr.is_const) ptr.child else @compileError(
"benchmark must be a const ptr to a struct with a 'run' method",
),
else => @compileError(
"benchmark must be a const ptr to a struct with a 'run' method",
),
};

// Check the benchmark parameter has a well typed run function.
_ = @as(fn (T, std.mem.Allocator) void, T.run);

try self.benchmarks.append(self.allocator, Definition{
.name = name,
.defn = .{ .parameterised = .{
.func = @ptrCast(&T.run),
.context = @ptrCast(benchmark),
} },
.config = optional(Config, config, self.common_config),
});
}
Expand Down Expand Up @@ -117,7 +156,10 @@ pub const Benchmark = struct {
defer if (defn.config.hooks.after_each) |hook| hook();

var t = try std.time.Timer.start();
defn.func(self.allocator);
switch (defn.defn) {
.simple => |func| func(self.allocator),
.parameterised => |x| x.func(@ptrCast(x.context), self.allocator),
}
return t.read();
}

Expand Down

0 comments on commit 5c1c39b

Please sign in to comment.