From 64640ee8884167c5d2d750ad3363bf9d9df9aaba Mon Sep 17 00:00:00 2001 From: dyu Date: Wed, 12 Jan 2022 18:26:10 +0800 Subject: [PATCH 1/2] benchmark instance --- bench.zig | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/bench.zig b/bench.zig index 1754432..6945437 100644 --- a/bench.zig +++ b/bench.zig @@ -9,7 +9,15 @@ const time = std.time; const Decl = std.builtin.TypeInfo.Declaration; -pub fn benchmark(comptime B: type) !void { +pub fn benchmark(type_or_instance: anytype) !void { + switch (@typeInfo(@TypeOf(type_or_instance))) { + .Type => try run(type_or_instance, type_or_instance), + .Pointer => |p| try run(p.child, type_or_instance), + else => @compileError("Pass a type or a pointer/instance to a struct."), + } +} + +fn run(comptime B: type, context: anytype) !void { const args = if (@hasDecl(B, "args")) B.args else [_]void{{}}; const arg_names = if (@hasDecl(B, "arg_names")) B.arg_names else [_]u8{}; const min_iterations = if (@hasDecl(B, "min_iterations")) B.min_iterations else 10000; @@ -84,8 +92,8 @@ pub fn benchmark(comptime B: type) !void { timer.reset(); const res = switch (@TypeOf(arg)) { - void => @field(B, def.name)(), - else => @field(B, def.name)(arg), + void => @field(context, def.name)(), + else => @field(context, def.name)(arg), }; const runtime = timer.read(); runtime_sum += runtime; @@ -244,3 +252,48 @@ test "benchmark generics" { } }); } + +test "benchmark instance" { + const iterations: usize = 1000; + const args = [_][]const u8{ "01" }; + const arg_names = [_][]const u8{ "01 x n" }; + + const capacity = args[0].len * iterations; + const BoundedArray = std.BoundedArray(u8, capacity); + const ArrayList = std.ArrayList(u8); + const allocator = std.testing.allocator; + + var instance = (struct { + const args = args; + const arg_names = arg_names; + const min_iterations = iterations; + const max_iterations = iterations; + + const Self = @This(); + bounded_array: BoundedArray, + non_resizing_list: ArrayList, + resizing_list: ArrayList, + + fn bounded_array_append_slice(self: *Self, data: []const u8) !void { + try self.bounded_array.appendSlice(data); + } + fn non_resizing_list_append_slice(self: *Self, data: []const u8) !void { + try self.non_resizing_list.appendSlice(data); + } + fn resizing_list_append_slice(self: *Self, data: []const u8) !void { + try self.resizing_list.appendSlice(data); + } + } { + .bounded_array = .{ .buffer = undefined, .len = 0 }, + .non_resizing_list = ArrayList.init(allocator), + .resizing_list = ArrayList.init(allocator), + }); + defer { + instance.non_resizing_list.deinit(); + instance.resizing_list.deinit(); + } + + try instance.non_resizing_list.ensureTotalCapacity(capacity); + + try benchmark(&instance); +} From 967e5e6aa50c6b4684a0fea999a04d55638e0b32 Mon Sep 17 00:00:00 2001 From: dyu Date: Wed, 12 Jan 2022 19:10:29 +0800 Subject: [PATCH 2/2] run opts which override static config --- bench.zig | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/bench.zig b/bench.zig index 6945437..888dc05 100644 --- a/bench.zig +++ b/bench.zig @@ -9,20 +9,32 @@ const time = std.time; const Decl = std.builtin.TypeInfo.Declaration; +pub const Opts = struct { + min_iterations: usize = 10000, + max_iterations: usize = 100000, + max_time: usize = 500 * time.ns_per_ms, +}; + pub fn benchmark(type_or_instance: anytype) !void { switch (@typeInfo(@TypeOf(type_or_instance))) { - .Type => try run(type_or_instance, type_or_instance), - .Pointer => |p| try run(p.child, type_or_instance), + .Type => try run(type_or_instance, type_or_instance, null), + .Pointer => |p| try run(p.child, type_or_instance, null), else => @compileError("Pass a type or a pointer/instance to a struct."), } } -fn run(comptime B: type, context: anytype) !void { +pub fn run(comptime B: type, context: anytype, run_opts: ?Opts) !void { const args = if (@hasDecl(B, "args")) B.args else [_]void{{}}; const arg_names = if (@hasDecl(B, "arg_names")) B.arg_names else [_]u8{}; - const min_iterations = if (@hasDecl(B, "min_iterations")) B.min_iterations else 10000; - const max_iterations = if (@hasDecl(B, "max_iterations")) B.max_iterations else 100000; - const max_time = 500 * time.ns_per_ms; + + var opts = Opts{}; + if (run_opts) |ro| { + opts = ro; + } else { + if (@hasDecl(B, "min_iterations")) opts.min_iterations = B.min_iterations; + if (@hasDecl(B, "max_iterations")) opts.max_iterations = B.max_iterations; + } + opts.max_iterations = math.max(opts.min_iterations, opts.max_iterations); const functions = comptime blk: { var res: []const Decl = &[_]Decl{}; @@ -86,8 +98,8 @@ fn run(comptime B: type, context: anytype) !void { var runtime_sum: u128 = 0; var i: usize = 0; - while (i < min_iterations or - (i < max_iterations and runtime_sum < max_time)) : (i += 1) + while (i < opts.min_iterations or + (i < opts.max_iterations and runtime_sum < opts.max_time)) : (i += 1) { timer.reset(); @@ -254,7 +266,7 @@ test "benchmark generics" { } test "benchmark instance" { - const iterations: usize = 1000; + const iterations: usize = 100000; const args = [_][]const u8{ "01" }; const arg_names = [_][]const u8{ "01 x n" }; @@ -296,4 +308,16 @@ test "benchmark instance" { try instance.non_resizing_list.ensureTotalCapacity(capacity); try benchmark(&instance); + + // reset + instance.bounded_array.len = 0; + instance.non_resizing_list.clearRetainingCapacity(); + instance.resizing_list.clearAndFree(); + + // run with fewer iterations + const fewer_iterations = iterations / 2; + try run(@TypeOf(instance), &instance, .{ + .min_iterations = fewer_iterations, + .max_iterations = fewer_iterations, + }); }