From db35f7b87c26a7906eeca632b79f2569d2d14599 Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Wed, 15 May 2024 17:58:46 -0700 Subject: [PATCH] Benchmark harness --- build.zig | 31 ++++++++++++++++++++++++------- src/bench.zig | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 src/bench.zig diff --git a/build.zig b/build.zig index 9fd3ecd..a0484c1 100644 --- a/build.zig +++ b/build.zig @@ -49,7 +49,7 @@ pub fn build(b: *std.Build) void { const native_library = b.addSharedLibrary(.{ .name = "zip8", - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); @@ -58,12 +58,31 @@ pub fn build(b: *std.Build) void { native_library.getEmittedBin(), b.fmt("libzip8{s}", .{target.result.dynamicLibSuffix()}), ); + b.default_step.dependOn(&native_library_install.step); + + const bench = b.addExecutable(.{ + .name = "bench", + .root_source_file = b.path("src/bench.zig"), + .target = target, + .optimize = optimize, + }); + bench.root_module.addImport("build_options", options_module); + const bench_runner = b.addInstallBinFile(bench.getEmittedBin(), "bench"); + const bench_install_step = b.step("bench", "Compile a benchmark harness"); + bench_install_step.dependOn(&bench_runner.step); + + const bench_run = b.addRunArtifact(bench); + if (b.args) |args| { + bench_run.addArgs(args); + } + const bench_run_step = b.step("run-bench", "Run the benchmark"); + bench_run_step.dependOn(&bench_run.step); const wasm_library = b.addExecutable(.{ .name = "zip8", // In this case the main source file is merely a path, however, in more // complicated build scripts, this could be a generated file. - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, @@ -103,7 +122,7 @@ pub fn build(b: *std.Build) void { .name = "zip8", // In this case the main source file is merely a path, however, in more // complicated build scripts, this could be a generated file. - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = b.resolveTargetQuery(.{ .cpu_arch = .thumb, .os_tag = .freestanding, @@ -118,7 +137,7 @@ pub fn build(b: *std.Build) void { // build a static library for AVR const atmega4809_library = b.addStaticLibrary(.{ .name = "zip8", - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = b.resolveTargetQuery(.{ .cpu_arch = .avr, .os_tag = .freestanding, @@ -192,11 +211,9 @@ pub fn build(b: *std.Build) void { const atmega4809_step = b.step("atmega4809", "Output a static library for ATmega4809"); atmega4809_step.dependOn(&atmega4809_library_install.step); - b.default_step.dependOn(&native_library_install.step); - // Creates a step for unit testing. const exe_tests = b.addTest(.{ - .root_source_file = .{ .path = "src/main.zig" }, + .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }); diff --git a/src/bench.zig b/src/bench.zig new file mode 100644 index 0000000..6e143f9 --- /dev/null +++ b/src/bench.zig @@ -0,0 +1,42 @@ +const std = @import("std"); + +const Cpu = @import("./cpu.zig"); + +pub const std_options = std.Options{ + .log_level = .warn, +}; + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const allocator = arena.allocator(); + const argv = try std.process.argsAlloc(allocator); + defer std.process.argsFree(allocator, argv); + + if (argv.len != 3) { + std.log.err("usage: {s} ", .{argv[0]}); + return error.BadUsage; + } + + const rom = try std.fs.cwd().readFileAlloc(allocator, argv[1], Cpu.memory_size - Cpu.initial_pc); + defer allocator.free(rom); + const instructions = try std.fmt.parseInt(usize, argv[2], 10); + + var cpu = try Cpu.init(rom, 0, .{0} ** 8); + + const before = std.posix.getrusage(std.posix.rusage.SELF); + for (0..instructions) |_| { + try cpu.cycle(); + cpu.dt = 0; + } + const after = std.posix.getrusage(std.posix.rusage.SELF); + const before_sec = @as(f64, @floatFromInt(before.utime.tv_sec)) + + @as(f64, @floatFromInt(before.utime.tv_usec)) / 1_000_000.0; + const after_sec = @as(f64, @floatFromInt(after.utime.tv_sec)) + + @as(f64, @floatFromInt(after.utime.tv_usec)) / 1_000_000.0; + const total_cpu_time = after_sec - before_sec; + const ins_per_sec = @as(f64, @floatFromInt(instructions)) / total_cpu_time; + + var s: [64]u8 = undefined; + const written = try std.fmt.bufPrint(&s, "{}", .{std.fmt.fmtIntSizeDec(@intFromFloat(ins_per_sec))}); + std.debug.print("{s} ins/sec\n", .{written[0 .. written.len - 1]}); +}