Skip to content

Commit 6ba1aa8

Browse files
committed
chore: wip
1 parent bd20e92 commit 6ba1aa8

11 files changed

Lines changed: 482 additions & 25 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
/.zig-cache
22
/zig-out
3+
baseline.json
4+
benchmark.folded
5+
benchmark_results.csv
6+
benchmark_results.json

README.md

Lines changed: 140 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ The `examples/` directory contains several complete examples:
262262
- `basic.zig` - Simple benchmarks comparing different operations
263263
- `async.zig` - Async/error-handling benchmark examples
264264
- `custom_options.zig` - Customizing benchmark parameters
265+
- `filtering_baseline.zig` - Benchmark filtering and baseline saving
266+
- `allocators.zig` - Comparing different allocator performance
267+
- `advanced_features.zig` - Complete demonstration of all advanced features
265268

266269
Run examples:
267270

@@ -273,6 +276,9 @@ zig build examples
273276
zig build run-basic
274277
zig build run-async
275278
zig build run-custom_options
279+
zig build run-filtering_baseline
280+
zig build run-allocators
281+
zig build run-advanced_features
276282
```
277283

278284
## Output Format
@@ -337,7 +343,7 @@ zig build run-basic
337343

338344
## Requirements
339345

340-
- Zig 0.13.0 or later
346+
- Zig 0.15.0 or later
341347

342348
## Contributing
343349

@@ -351,16 +357,140 @@ MIT License - see LICENSE file for details
351357

352358
Inspired by [mitata](https://github.com/evanwashere/mitata), a beautiful JavaScript benchmarking library.
353359

354-
## Roadmap
360+
## Advanced Features
355361

356-
- [ ] JSON/CSV export for results
357-
- [ ] Historical comparison (compare against saved baselines)
358-
- [ ] Memory profiling integration
359-
- [ ] Flamegraph generation support
360-
- [ ] CI/CD integration helpers
361-
- [ ] Regression detection
362-
- [ ] Custom allocator benchmarking
363-
- [ ] Benchmark filtering (run specific benchmarks by pattern)
362+
All advanced features are now implemented and available! See the `examples/advanced_features.zig` for a complete demonstration.
363+
364+
### ✅ Implemented Features
365+
366+
- **JSON/CSV Export** - Export benchmark results to JSON or CSV format
367+
- **Historical Comparison** - Compare current results against saved baselines with regression detection
368+
- **Memory Profiling** - Track memory allocations, peak usage, and allocation counts
369+
- **Flamegraph Support** - Generate flamegraph-compatible folded stack format and profiler instructions
370+
- **CI/CD Integration** - Built-in helpers for GitHub Actions, GitLab CI, and generic CI systems
371+
- **Regression Detection** - Automatic detection of performance regressions with configurable thresholds
372+
- **Custom Allocator Benchmarking** - Built-in support for benchmarking with different allocators
373+
- **Benchmark Filtering** - Run specific benchmarks by name pattern
374+
375+
### Export Results to JSON/CSV
376+
377+
```zig
378+
const export_mod = @import("export");
379+
380+
const exporter = export_mod.Exporter.init(allocator);
381+
382+
// Export to JSON
383+
try exporter.exportToFile(results, "benchmark_results.json", .json);
384+
385+
// Export to CSV
386+
try exporter.exportToFile(results, "benchmark_results.csv", .csv);
387+
```
388+
389+
### Baseline Comparison & Regression Detection
390+
391+
```zig
392+
const comparison_mod = @import("comparison");
393+
394+
// Create comparator with 10% regression threshold
395+
const comparator = comparison_mod.Comparator.init(allocator, 10.0);
396+
397+
// Compare current results against baseline
398+
const comparisons = try comparator.compare(results, "baseline.json");
399+
defer allocator.free(comparisons);
400+
401+
// Print comparison report
402+
try comparator.printComparison(stdout, comparisons);
403+
```
404+
405+
### Memory Profiling
406+
407+
```zig
408+
const memory_profiler = @import("memory_profiler");
409+
410+
// Create profiling allocator
411+
var profiling_allocator = memory_profiler.ProfilingAllocator.init(base_allocator);
412+
const tracked_allocator = profiling_allocator.allocator();
413+
414+
// Run benchmark with tracked allocator
415+
// ... benchmark code ...
416+
417+
// Get memory statistics
418+
const stats = profiling_allocator.getStats();
419+
// stats contains: peak_allocated, total_allocated, total_freed,
420+
// current_allocated, allocation_count, free_count
421+
```
422+
423+
### CI/CD Integration
424+
425+
```zig
426+
const ci = @import("ci");
427+
428+
// Detect CI environment automatically
429+
const ci_format = ci.detectCIEnvironment();
430+
431+
// Create CI helper with configuration
432+
var ci_helper = ci.CIHelper.init(allocator, .{
433+
.fail_on_regression = true,
434+
.regression_threshold = 10.0,
435+
.baseline_path = "baseline.json",
436+
.output_format = ci_format,
437+
});
438+
439+
// Generate CI-specific summary
440+
try ci_helper.generateSummary(results);
441+
442+
// Check for regressions
443+
const has_regression = try ci_helper.checkRegressions(results);
444+
if (has_regression and ci_helper.shouldFailBuild(has_regression)) {
445+
std.process.exit(1); // Fail the build
446+
}
447+
```
448+
449+
### Flamegraph Generation
450+
451+
```zig
452+
const flamegraph_mod = @import("flamegraph");
453+
454+
const flamegraph_gen = flamegraph_mod.FlamegraphGenerator.init(allocator);
455+
456+
// Generate folded stack format for flamegraph.pl
457+
try flamegraph_gen.generateFoldedStacks("benchmark.folded", "MyBenchmark", 10000);
458+
459+
// Generate profiler instructions
460+
try flamegraph_gen.generateInstructions(stdout, "my_executable");
461+
462+
// Detect available profilers
463+
const recommended = flamegraph_mod.ProfilerIntegration.recommendProfiler();
464+
```
465+
466+
### Benchmark Filtering
467+
468+
```zig
469+
var suite = bench.BenchmarkSuite.init(allocator);
470+
defer suite.deinit();
471+
472+
try suite.add("Fast Operation", fastOp);
473+
try suite.add("Slow Operation", slowOp);
474+
try suite.add("Fast Algorithm", fastAlgo);
475+
476+
// Only run benchmarks matching "Fast"
477+
suite.setFilter("Fast");
478+
479+
try suite.run(); // Only runs "Fast Operation" and "Fast Algorithm"
480+
```
481+
482+
### Custom Allocator Benchmarking
483+
484+
```zig
485+
var suite = bench.BenchmarkSuite.init(allocator);
486+
defer suite.deinit();
487+
488+
// Benchmark with custom allocator
489+
try suite.addWithAllocator("GPA Benchmark", benchmarkFunc, gpa_allocator);
490+
try suite.addWithAllocator("Arena Benchmark", benchmarkFunc, arena_allocator);
491+
492+
try suite.run();
493+
```
364494

365495
## FAQ
366496

build.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ pub fn build(b: *std.Build) void {
3030
ci_module.addImport("bench", bench_module);
3131
ci_module.addImport("comparison", comparison_module);
3232

33+
const flamegraph_module = b.createModule(.{
34+
.root_source_file = b.path("src/flamegraph.zig"),
35+
});
36+
3337
// Example executables
3438
const examples = [_]struct {
3539
name: []const u8,
@@ -57,6 +61,7 @@ pub fn build(b: *std.Build) void {
5761
exe_module.addImport("comparison", comparison_module);
5862
exe_module.addImport("memory_profiler", memory_profiler_module);
5963
exe_module.addImport("ci", ci_module);
64+
exe_module.addImport("flamegraph", flamegraph_module);
6065
}
6166

6267
const exe = b.addExecutable(.{
@@ -96,6 +101,7 @@ pub fn build(b: *std.Build) void {
96101
exe_module.addImport("comparison", comparison_module);
97102
exe_module.addImport("memory_profiler", memory_profiler_module);
98103
exe_module.addImport("ci", ci_module);
104+
exe_module.addImport("flamegraph", flamegraph_module);
99105
}
100106

101107
const exe = b.addExecutable(.{

examples/advanced_features.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const export_mod = @import("export");
66
const comparison_mod = @import("comparison");
77
const memory_profiler = @import("memory_profiler");
88
const ci = @import("ci");
9+
const flamegraph_mod = @import("flamegraph");
910

1011
var global_sum: u64 = 0;
1112

@@ -153,5 +154,22 @@ pub fn main() !void {
153154
}
154155
}
155156

157+
// 6. Flamegraph Support Demo
158+
std.debug.print("\n{s}=== Flamegraph Support Demo ==={s}\n", .{ bench.Formatter.BOLD, bench.Formatter.RESET });
159+
160+
const flamegraph_gen = flamegraph_mod.FlamegraphGenerator.init(allocator);
161+
162+
// Generate folded stack format
163+
try flamegraph_gen.generateFoldedStacks("benchmark.folded", "Fast Benchmark", 10000);
164+
165+
// Show instructions for profiling
166+
std.debug.print("\n{s}Profiler Detection:{s}\n", .{ bench.Formatter.BOLD, bench.Formatter.RESET });
167+
const recommended = flamegraph_mod.ProfilerIntegration.recommendProfiler();
168+
std.debug.print(" Recommended profiler for your platform: {s}\n", .{recommended});
169+
170+
// Generate call tree
171+
try flamegraph_gen.generateCallTree(stdout, "Fast Benchmark", 162);
172+
156173
std.debug.print("\n{s}✓ Advanced features demo complete!{s}\n", .{ bench.Formatter.GREEN, bench.Formatter.RESET });
174+
std.debug.print("{s}✓ All 6 advanced features demonstrated successfully!{s}\n", .{ bench.Formatter.GREEN, bench.Formatter.RESET });
157175
}

src/advanced.zig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub const export_mod = @import("export");
33
pub const comparison = @import("comparison");
44
pub const memory_profiler = @import("memory_profiler");
55
pub const ci = @import("ci");
6+
pub const flamegraph = @import("flamegraph");
67

78
pub const Exporter = export_mod.Exporter;
89
pub const ExportFormat = export_mod.ExportFormat;
@@ -18,3 +19,6 @@ pub const CIHelper = ci.CIHelper;
1819
pub const CIConfig = ci.CIConfig;
1920
pub const OutputFormat = ci.OutputFormat;
2021
pub const detectCIEnvironment = ci.detectCIEnvironment;
22+
23+
pub const FlamegraphGenerator = flamegraph.FlamegraphGenerator;
24+
pub const ProfilerIntegration = flamegraph.ProfilerIntegration;

0 commit comments

Comments
 (0)