○
Planned This feature is planned but not yet implemented.
Event tap code injection not yet implemented
Code
// PERFORMANCE TEST: Event taps overhead vs manual instrumentation
// Goal: Prove taps have same cost as manual function calls
// Loop 1 million times with 5 tap points
// Baseline: Zig with manual function calls at same points
// Threshold: 1.05x (5% slower max)
const std = @import("std");
// Counter for tap calls (verify taps actually run)
var tap_count: u64 = 0;
// Event for loop iteration
~tor count { i: u64 } -> u64
~proc count|zig {
if (i < 1_000_000) {
return i + 1;
} else {
}
}
// Tap target - simulates logging/metrics
~tor tap-point { i: u64 }
~proc tap-point|zig {
tap_count += 1;
// Touch parameter to avoid unused warning
if (i > 999_999_999) {
std.debug.print("Impossible\n", .{});
}
}
// Print result
~tor print-result {}
~proc print-result|zig {
std.debug.print("Taps called: {}\n", .{tap_count});
}
// Taps: Observe every 5th iteration (5 tap points)
~count -> * | next n where n.i % 200_000 == 0 |> tap-point(n.i) | done |> _
~count -> * | next n where n.i % 200_001 == 0 |> tap-point(n.i) | done |> _
~count -> * | next n where n.i % 200_002 == 0 |> tap-point(n.i) | done |> _
~count -> * | next n where n.i % 200_003 == 0 |> tap-point(n.i) | done |> _
~count -> * | next n where n.i % 200_004 == 0 |> tap-point(n.i) | done |> _
// Main loop
~#loop count(i: 0): n |> @loop(n.i)
|> print-result() | done |> _
Supporting Files
// Hand-written Zig baseline with manual instrumentation
// Simulates what event taps compile to: function calls at emission sites
const std = @import("std");
var tap_count: u64 = 0;
// Simulates the tap function
fn tap_point(i: u64) void {
tap_count += 1;
// Touch parameter to avoid unused warning
if (i > 999_999_999) {
std.debug.print("Impossible\n", .{});
}
}
fn count_with_taps() void {
var i: u64 = 0;
while (i < 1_000_000) : (i += 1) {
// Manual "taps" - function calls at the same points Koru taps would fire
if (i % 200_000 == 0) tap_point(i);
if (i % 200_001 == 0) tap_point(i);
if (i % 200_002 == 0) tap_point(i);
if (i % 200_003 == 0) tap_point(i);
if (i % 200_004 == 0) tap_point(i);
}
}
pub fn main() !void {
count_with_taps();
std.debug.print("Taps called: {}\n", .{tap_count});
}
#!/bin/bash
# Benchmark: Simple loop
# Compare Koru vs hand-written Zig
set -e
echo "Building baseline (Zig)..."
zig build-exe baseline.zig -O ReleaseFast
echo "Building Koru version..."
# Assuming output_emitted.zig or output exists from test runner
if [ -f "output_emitted.zig" ]; then
zig build-exe output_emitted.zig -O ReleaseFast -femit-bin=koru_output
elif [ -f "output" ]; then
# Already compiled, copy it
cp output koru_output
chmod +x koru_output
else
echo "ERROR: No Koru output found (output_emitted.zig or output)"
exit 1
fi
echo ""
echo "Running benchmarks with hyperfine..."
# Check if hyperfine is installed
if ! command -v hyperfine &> /dev/null; then
echo "ERROR: hyperfine not installed"
echo "Install with: brew install hyperfine (macOS) or cargo install hyperfine"
exit 1
fi
# Run benchmark
# Use --shell=none to avoid shell startup overhead (benchmarks are <5ms)
# Use more runs for better statistics on fast benchmarks
hyperfine --warmup 5 --runs 30 --shell=none \
--export-json results.json \
--command-name "Baseline (Zig)" './baseline' \
--command-name "Koru" './koru_output'
echo ""
echo "Benchmark complete! Results saved to results.json"
Test Configuration
MUST_RUN THRESHOLD 1.05
Post-validation Script:
#!/bin/bash
# Post-validation: Check performance is within threshold
set -e
if [ ! -f "results.json" ]; then
echo "⚠️ No benchmark results found (results.json missing)"
echo " Running benchmark..."
bash benchmark.sh
fi
if [ ! -f "results.json" ]; then
echo "❌ FAIL: Benchmark did not produce results.json"
exit 1
fi
# Check if jq is installed
if ! command -v jq &> /dev/null; then
echo "⚠️ jq not installed (needed to parse benchmark results)"
echo " Install with: brew install jq (macOS) or apt install jq (Linux)"
echo " Skipping performance validation..."
exit 0
fi
THRESHOLD=$(cat THRESHOLD)
# Parse results (hyperfine format)
BASELINE_TIME=$(jq -r '.results[0].mean' results.json)
KORU_TIME=$(jq -r '.results[1].mean' results.json)
# Calculate ratio (Koru / Baseline)
RATIO=$(echo "scale=4; $KORU_TIME / $BASELINE_TIME" | bc -l)
echo ""
echo "Performance Results:"
echo " Baseline (Zig): ${BASELINE_TIME}s"
echo " Koru: ${KORU_TIME}s"
echo " Ratio: ${RATIO}x"
echo " Threshold: ${THRESHOLD}x"
echo ""
# Compare to threshold
if (( $(echo "$RATIO > $THRESHOLD" | bc -l) )); then
echo "❌ PERFORMANCE REGRESSION!"
echo " Koru is ${RATIO}x slower than baseline"
echo " Threshold is ${THRESHOLD}x"
echo " Regression: $(echo "scale=1; ($RATIO - 1) * 100" | bc -l)%"
exit 1
elif (( $(echo "$RATIO < 0.95" | bc -l) )); then
echo "✅ PERFORMANCE IMPROVED!"
echo " Koru is FASTER than baseline (${RATIO}x)"
else
echo "✅ Performance within threshold"
echo " Overhead: $(echo "scale=1; ($RATIO - 1) * 100" | bc -l)%"
fi
exit 0