Usage
The 23 examples below are taken from zig-benchmarks's README.
.{
.name = "my-project",
.version = "0.1.0",
.dependencies = .{
.bench = .{
.url = "https://github.com/yourusername/zig-bench/archive/main.tar.gz",
.hash = "...",
},
},
}
const bench = b.dependency("bench", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("bench", bench.module("bench"));
const bench_module = b.addModule("bench", .{
.root_source_file = b.path("path/to/zig-bench/src/bench.zig"),
});
exe.root_module.addImport("bench", bench_module);
const std = @import("std");
const bench = @import("bench");
var global_sum: u64 = 0;
fn benchmarkLoop() void {
var sum: u64 = 0;
var i: u32 = 0;
while (i < 1000) : (i += 1) {
sum += i;
}
global_sum = sum;
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var suite = bench.BenchmarkSuite.init(allocator);
defer suite.deinit();
try suite.add("Loop 1000 times", benchmarkLoop);
try suite.run();
}
const std = @import("std");
const bench = @import("bench");
var result: u64 = 0;
fn fibonacci(n: u32) u64 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
fn benchFib20() void {
result = fibonacci(20);
}
fn benchFib25() void {
result = fibonacci(25);
}
fn benchFib30() void {
result = fibonacci(30);
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var suite = bench.BenchmarkSuite.init(allocator);
defer suite.deinit();
try suite.add("Fibonacci(20)", benchFib20);
try suite.add("Fibonacci(25)", benchFib25);
try suite.add("Fibonacci(30)", benchFib30);
try suite.run();
}
const std = @import("std");
const bench = @import("bench");
fn slowOperation() void {
var sum: u64 = 0;
var i: u32 = 0;
while (i < 10_000_000) : (i += 1) {
sum += i;
}
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var suite = bench.BenchmarkSuite.init(allocator);
defer suite.deinit();
try suite.addWithOptions("Slow Operation", slowOperation, .{
.warmup_iterations = 2, // Fewer warmup iterations
.min_iterations = 5, // Minimum iterations to run
.max_iterations = 50, // Maximum iterations
.min_time_ns = 2_000_000_000, // Run for at least 2 seconds
});
try suite.run();
}
const std = @import("std");
const bench = @import("bench");
const async_bench = bench.async_bench;
var result: []u8 = undefined;
fn asyncOperation() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var buffer = try allocator.alloc(u8, 1024);
defer allocator.free(buffer);
@memset(buffer, 'A');
result = buffer;
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
var suite = async_bench.AsyncBenchmarkSuite.init(allocator);
defer suite.deinit();
try suite.add("Async Buffer Allocation", asyncOperation);
try suite.run();
}
pub const BenchmarkSuite = struct {
pub fn init(allocator: Allocator) BenchmarkSuite
pub fn deinit(self: *BenchmarkSuite) void
pub fn add(self: *BenchmarkSuite, name: []const u8, func: *const fn () void) !void
pub fn addWithOptions(self: *BenchmarkSuite, name: []const u8, func: *const fn () void, opts: BenchmarkOptions) !void
pub fn run(self: *BenchmarkSuite) !void
};
pub const BenchmarkOptions = struct {
warmup_iterations: u32 = 5, // Number of warmup runs
min_iterations: u32 = 10, // Minimum iterations to execute
max_iterations: u32 = 10_000, // Maximum iterations to execute
min_time_ns: u64 = 1_000_000_000, // Minimum time to run (1 second)
baseline: ?[]const u8 = null, // Reserved for future baseline comparison
};
pub const BenchmarkResult = struct {
name: []const u8,
samples: std.ArrayList(u64),
mean: f64, // Mean execution time in nanoseconds
stddev: f64, // Standard deviation
min: u64, // Minimum time
max: u64, // Maximum time
p50: u64, // 50th percentile (median)
p75: u64, // 75th percentile
p99: u64, // 99th percentile
ops_per_sec: f64, // Operations per second
iterations: u64, // Total iterations executed
};
pub const AsyncBenchmarkSuite = struct {
pub fn init(allocator: Allocator) AsyncBenchmarkSuite
pub fn deinit(self: *AsyncBenchmarkSuite) void
pub fn add(self: *AsyncBenchmarkSuite, name: []const u8, func: *const fn () anyerror!void) !void
pub fn addWithOptions(self: *AsyncBenchmarkSuite, name: []const u8, func: *const fn () anyerror!void, opts: BenchmarkOptions) !void
pub fn run(self: *AsyncBenchmarkSuite) !void
};
const export_mod = @import("export");
const exporter = export_mod.Exporter.init(allocator);
// Export to JSON
try exporter.exportToFile(results, "benchmark_results.json", .json);
// Export to CSV
try exporter.exportToFile(results, "benchmark_results.csv", .csv);
const comparison_mod = @import("comparison");
// Create comparator with 10% regression threshold
const comparator = comparison_mod.Comparator.init(allocator, 10.0);
// Compare current results against baseline
const comparisons = try comparator.compare(results, "baseline.json");
defer allocator.free(comparisons);
// Print comparison report
try comparator.printComparison(stdout, comparisons);
const memory_profiler = @import("memory_profiler");
// Create profiling allocator
var profiling_allocator = memory_profiler.ProfilingAllocator.init(base_allocator);
const tracked_allocator = profiling_allocator.allocator();
// Run benchmark with tracked allocator
// ... benchmark code ...
// Get memory statistics
const stats = profiling_allocator.getStats();
// stats contains: peak_allocated, total_allocated, total_freed,
// current_allocated, allocation_count, free_count
const ci = @import("ci");
// Detect CI environment automatically
const ci_format = ci.detectCIEnvironment();
// Create CI helper with configuration
var ci_helper = ci.CIHelper.init(allocator, .{
.fail_on_regression = true,
.regression_threshold = 10.0,
.baseline_path = "baseline.json",
.output_format = ci_format,
});
// Generate CI-specific summary
try ci_helper.generateSummary(results);
// Check for regressions
const has_regression = try ci_helper.checkRegressions(results);
if (has_regression and ci_helper.shouldFailBuild(has_regression)) {
std.process.exit(1); // Fail the build
}
const flamegraph_mod = @import("flamegraph");
const flamegraph_gen = flamegraph_mod.FlamegraphGenerator.init(allocator);
// Generate folded stack format for flamegraph.pl
try flamegraph_gen.generateFoldedStacks("benchmark.folded", "MyBenchmark", 10000);
// Generate profiler instructions
try flamegraph_gen.generateInstructions(stdout, "my_executable");
// Detect available profilers
const recommended = flamegraph_mod.ProfilerIntegration.recommendProfiler();
var suite = bench.BenchmarkSuite.init(allocator);
defer suite.deinit();
try suite.add("Fast Operation", fastOp);
try suite.add("Slow Operation", slowOp);
try suite.add("Fast Algorithm", fastAlgo);
// Only run benchmarks matching "Fast"
suite.setFilter("Fast");
try suite.run(); // Only runs "Fast Operation" and "Fast Algorithm"
var suite = bench.BenchmarkSuite.init(allocator);
defer suite.deinit();
// Benchmark with custom allocator
try suite.addWithAllocator("GPA Benchmark", benchmarkFunc, gpa_allocator);
try suite.addWithAllocator("Arena Benchmark", benchmarkFunc, arena_allocator);
try suite.run();
const groups = @import("groups");
var manager = groups.GroupManager.init(allocator);
defer manager.deinit();
// Create groups
var algorithms = try manager.addGroup("Algorithms");
try algorithms.add("QuickSort", quicksortBench);
try algorithms.add("MergeSort", mergesortBench);
var io = try manager.addGroup("I/O Operations");
try io.add("File Read", fileReadBench);
try io.add("File Write", fileWriteBench);
// Run all groups
try manager.runAll();
// Or run specific group
try manager.runGroup("Algorithms");
const warmup = @import("warmup");
const detector = warmup.WarmupDetector.initDefault();
const result = try detector.detect(myBenchFunc, allocator);
std.debug.print("Optimal warmup: {d} iterations\n", .{result.optimal_iterations});
std.debug.print("Stabilized: {}\n", .{result.stabilized});
std.debug.print("CV: {d:.4}\n", .{result.final_cv});
const outliers = @import("outliers");
// Configure outlier detection
const config = outliers.OutlierConfig{
.method = .iqr, // or .zscore, .mad
.iqr_multiplier = 1.5,
};
const detector = outliers.OutlierDetector.init(config);
var result = try detector.detectAndRemove(samples, allocator);
defer result.deinit();
std.debug.print("Removed {d} outliers ({d:.2}%)\n", .{
result.outlier_count,
result.outlier_percentage,
});
const param = @import("parameterized");
// Define sizes to test
const sizes = [_]usize{ 10, 100, 1000, 10000 };
// Create parameterized benchmark
var suite = try param.sizeParameterized(
allocator,
"Array Sort",
arraySortBench,
&sizes,
);
defer suite.deinit();
try suite.run();
const parallel = @import("parallel");
// Single parallel benchmark
const config = parallel.ParallelConfig{
.thread_count = 4,
.iterations_per_thread = 1000,
};
const pb = parallel.ParallelBenchmark.init(allocator, "Parallel Op", func, config);
var result = try pb.run();
defer result.deinit();
try parallel.ParallelBenchmark.printResult(&result);
// Scalability test across thread counts
const thread_counts = [_]usize{ 1, 2, 4, 8 };
const scalability = parallel.ScalabilityTest.init(
allocator,
"Scalability",
func,
&thread_counts,
1000,
);
try scalability.run();