Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,19 @@ pub fn main() !void {

Run it and you will get the following output:

| Benchmark | Time | Relative | Iterations | Ops/s | Cycles | Instructions | IPC | Cache Misses |
| :---------------- | ------: | -------: | ---------: | -------: | -----: | -----------: | ---: | -----------: |
| `fibNaive/30` | 1.77 ms | 1.00x | 1 | 564.7/s | 8.1M | 27.8M | 3.41 | 0.3 |
| `fibIterative/30` | 3.44 ns | 0.00x | 300006 | 290.7M/s | 15.9 | 82.0 | 5.15 | 0.0 |
```markdown
| Benchmark | Time | Speedup | Iterations | Ops/s | Cycles | Instructions | IPC | Cache Misses |
| :---------------- | ------: | ---------: | ---------: | -------: | -----: | -----------: | ---: | -----------: |
| `fibNaive/30` | 1.78 ms | 1.00x | 1 | 563.2/s | 8.1M | 27.8M | 3.41 | 0.3 |
| `fibIterative/30` | 3.44 ns | 516055.19x | 300006 | 290.6M/s | 15.9 | 82.0 | 5.15 | 0.0 |
```

The benchmark report can be copy-paste directly to Markdown file:

Yes, the output is markdown table.
| Benchmark | Time | Speedup | Iterations | Ops/s | Cycles | Instructions | IPC | Cache Misses |
| :---------------- | ------: | ---------: | ---------: | -------: | -----: | -----------: | ---: | -----------: |
| `fibNaive/30` | 1.78 ms | 1.00x | 1 | 563.2/s | 8.1M | 27.8M | 3.41 | 0.3 |
| `fibIterative/30` | 3.44 ns | 516055.19x | 300006 | 290.6M/s | 15.9 | 82.0 | 5.15 | 0.0 |

## Features

Expand Down Expand Up @@ -207,11 +214,11 @@ const res = try bench.run(allocator, "Heavy Task", heavyFn, .{
The default bench.report prints a clean, Markdown-compatible table to stdout. It
automatically handles unit scaling (`ns`, `us`, `ms`, `s`) and formatting.

```sh
| Benchmark | Time | Relative | Iterations | Ops/s | Cycles | Instructions | IPC | Cache Misses |
| :---------------- | ------: | -------: | ---------: | -------: | -----: | -----------: | ---: | -----------: |
| `fibNaive/30` | 1.77 ms | 1.00x | 1 | 564.7/s | 8.1M | 27.8M | 3.41 | 0.3 |
| `fibIterative/30` | 3.44 ns | 0.00x | 300006 | 290.7M/s | 15.9 | 82.0 | 5.15 | 0.0 |
```markdown
| Benchmark | Time | Speedup | Iterations | Ops/s | Cycles | Instructions | IPC | Cache Misses |
| :---------------- | ------: | ---------: | ---------: | -------: | -----: | -----------: | ---: | -----------: |
| `fibNaive/30` | 1.78 ms | 1.00x | 1 | 563.2/s | 8.1M | 27.8M | 3.41 | 0.3 |
| `fibIterative/30` | 3.44 ns | 516055.19x | 300006 | 290.6M/s | 15.9 | 82.0 | 5.15 | 0.0 |
```

### Custom Reporter
Expand Down
14 changes: 7 additions & 7 deletions src/Reporter.test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ test "Reporter: Hardware Counters (Sparse Data)" {

test "Reporter: Baseline Comparison" {
const m_base = createMetrics("Base", 100.0); // Baseline (100ns)
const m_fast = createMetrics("Fast", 50.0); // 2x faster (0.50x duration)
const m_slow = createMetrics("Slow", 200.0); // 2x slower (2.00x duration)
const m_fast = createMetrics("Fast", 50.0); // 2x faster (2.00x speedup)
const m_slow = createMetrics("Slow", 200.0); // 2x slower (0.50x speedup)

var buffer: [16 * 1024]u8 = undefined;
var w: Writer = .fixed(&buffer);
Expand All @@ -110,11 +110,11 @@ test "Reporter: Baseline Comparison" {
try Reporter.write(&w, .{ .metrics = &.{ m_base, m_fast, m_slow }, .baseline_index = 0 });

const expected =
"| Benchmark | Time | Relative | Iterations | Ops/s | \n" ++
"| :-------- | --------: | -------: | ---------: | ------: | \n" ++
"| `Base` | 100.00 ns | 1.00x | 1000000 | 10.0M/s | \n" ++
"| `Fast` | 50.00 ns | 0.50x | 1000000 | 20.0M/s | \n" ++
"| `Slow` | 200.00 ns | 2.00x | 1000000 | 5.0M/s | \n";
"| Benchmark | Time | Speedup | Iterations | Ops/s | \n" ++
"| :-------- | --------: | ------: | ---------: | ------: | \n" ++
"| `Base` | 100.00 ns | 1.00x | 1000000 | 10.0M/s | \n" ++
"| `Fast` | 50.00 ns | 2.00x | 1000000 | 20.0M/s | \n" ++
"| `Slow` | 200.00 ns | 0.50x | 1000000 | 5.0M/s | \n";

try testing.expectEqualStrings(expected, w.buffered());
}
22 changes: 11 additions & 11 deletions src/Reporter.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn write(w: *Writer, options: Options) !void {
// Initialize columns with Header names and default visibility
var col_name = Column{ .title = "Benchmark", .width = 0, .align_right = false, .active = true };
var col_time = Column{ .title = "Time", .width = 0, .align_right = true, .active = true };
var col_relative = Column{ .title = "Relative", .width = 0, .align_right = true, .active = false };
var col_speedup = Column{ .title = "Speedup", .width = 0, .align_right = true, .active = false };
var col_iter = Column{ .title = "Iterations", .width = 0, .align_right = true, .active = true };

var col_bytes = Column{ .title = "Bytes/s", .width = 0, .align_right = true, .active = false };
Expand All @@ -43,14 +43,14 @@ pub fn write(w: *Writer, options: Options) !void {
// Activate Rel column if baseline_index is valid
if (options.baseline_index) |idx| {
if (idx < options.metrics.len) {
col_relative.active = true;
col_speedup.active = true;
}
}

// Check headers first
col_name.width = col_name.title.len;
col_time.width = col_time.title.len;
col_relative.width = col_relative.title.len;
col_speedup.width = col_speedup.title.len;
// col_cpu.width = col_cpu.title.len;
col_iter.width = col_iter.title.len;
col_bytes.width = col_bytes.title.len;
Expand All @@ -69,12 +69,12 @@ pub fn write(w: *Writer, options: Options) !void {
col_time.width = @max(col_time.width, s_time.len);

// Relative
if (col_relative.active) {
if (col_speedup.active) {
const base = options.metrics[options.baseline_index.?];
// Avoid division by zero
const ratio = if (base.mean_ns > 0) m.mean_ns / base.mean_ns else 0;
const ratio = if (m.mean_ns > 0) base.mean_ns / m.mean_ns else 0;
const s_rel = try std.fmt.bufPrint(&buf, "{d:.2}x", .{ratio});
col_relative.width = @max(col_relative.width, s_rel.len);
col_speedup.width = @max(col_speedup.width, s_rel.len);
}

// Iterations
Expand Down Expand Up @@ -119,7 +119,7 @@ pub fn write(w: *Writer, options: Options) !void {
try w.writeAll("| ");
try printCell(w, col_name.title, col_name);
try printCell(w, col_time.title, col_time);
if (col_relative.active) try printCell(w, col_relative.title, col_relative);
if (col_speedup.active) try printCell(w, col_speedup.title, col_speedup);
try printCell(w, col_iter.title, col_iter);
if (col_bytes.active) try printCell(w, col_bytes.title, col_bytes);
if (col_ops.active) try printCell(w, col_ops.title, col_ops);
Expand All @@ -133,7 +133,7 @@ pub fn write(w: *Writer, options: Options) !void {
try w.writeAll("| ");
try printDivider(w, col_name);
try printDivider(w, col_time);
if (col_relative.active) try printDivider(w, col_relative);
if (col_speedup.active) try printDivider(w, col_speedup);
try printDivider(w, col_iter);
if (col_bytes.active) try printDivider(w, col_bytes);
if (col_ops.active) try printDivider(w, col_ops);
Expand All @@ -155,11 +155,11 @@ pub fn write(w: *Writer, options: Options) !void {
try printCell(w, try fmtTime(&buf, m.mean_ns), col_time);

// Relative
if (col_relative.active) {
if (col_speedup.active) {
const base = options.metrics[options.baseline_index.?];
const ratio = if (base.mean_ns > 0) m.mean_ns / base.mean_ns else 0;
const ratio = if (m.mean_ns > 0) base.mean_ns / m.mean_ns else 0;
const s_rel = try std.fmt.bufPrint(&buf, "{d:.2}x", .{ratio});
try printCell(w, s_rel, col_relative);
try printCell(w, s_rel, col_speedup);
}

// Iterations
Expand Down