○
Planned This feature is planned but not yet implemented.
OWED: label loops (#/@) compile and run the 10M-count performance shape.
Error Details
output_emitted.zig:149:59: error: type 'u64' does not support field access
Failure Output
🎯 Compiler coordination: Passes: 20 (flow-based: elaborate, analysis, emission)
Error: output_emitted.zig:149:59: error: type 'u64' does not support field access
_ = main_module.print_event.handler(.{ .result = d.result });
~^~~~~~~
referenced by:
main: output_emitted.zig:197:22
callMain [inlined]: /opt/homebrew/Cellar/zig/0.15.2_1/lib/zig/std/start.zig:618:22
callMainWithArgs [inlined]: /opt/homebrew/Cellar/zig/0.15.2_1/lib/zig/std/start.zig:587:20
main: /opt/homebrew/Cellar/zig/0.15.2_1/lib/zig/std/start.zig:602:28
1 reference(s) hidden; use '-freference-trace=5' to see all references Code
// PERFORMANCE TEST: Koru label loops vs Zig while loops
// Goal: Prove Koru loops (#/@) compile to same code as Zig while loops
// Based on working test: 203_labels_and_jumps
// Loop: Count to 10 million (runs 10ms for better benchmark accuracy)
// Baseline: Zig while loop
// Threshold: 1.05x (5% slower max)
const std = @import("std");
// Event for counting/summing
~tor count { i: u64, sum: u64 }
| next { i: u64, sum: u64 }
| done u64
~proc count|zig {
const new_i = i + 1;
const new_sum = sum + i;
if (new_i < 10_000_000) {
return .{ .next = .{ .i = new_i, .sum = new_sum } };
} else {
return .{ .done = new_sum };
}
}
// Print result
~tor print { result: u64 }
~proc print|zig {
std.debug.print("Sum: {}\n", .{result});
}
// Loop: count to 1 million
~#loop count(i: 0, sum: 0)
| next n |> @loop(n.i, n.sum)
| done d |> print(d.result)
Supporting Files
// Hand-written Zig baseline for label loops
// This is what Koru label loops (#/@) SHOULD compile to
//
// Tests:
// 1. Live loop (sum 0 to 1M) - should be optimized well
// 2. Dead loop (unused result) - should be eliminated entirely
const std = @import("std");
fn count_to_million() u64 {
var sum: u64 = 0;
var i: u64 = 0;
while (i < 10_000_000) : (i += 1) {
sum += i;
}
return sum;
}
// Dead loop - compiler should eliminate this entirely
fn dead_loop() void {
var i: u64 = 0;
while (i < 1_000_000) : (i += 1) {
// Do nothing
}
}
pub fn main() !void {
// Live loop
const result = count_to_million();
std.debug.print("Sum: {}\n", .{result});
// Dead loop - result unused
// In -O ReleaseFast, Zig should eliminate this entirely
dead_loop();
}
#!/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"
// MINIMAL TEST: Does label loop work at all?
// Just count to 10 and print each iteration
const std = @import("std");
// Count event - loop controller
~tor count { i: u64 }
| next u64
~proc count|zig {
if (i < 10) {
return .{ .next = i + 1 };
} else {
}
}
// Print event
~tor print { i: u64 }
~proc print|zig {
std.debug.print("i = {}\n", .{i});
}
// Loop: count and print each iteration
~#loop count(i: 0)
| next n |> print(n.i) |> @loop(n.i)
#!/bin/bash
# Inspect what code was actually generated
# Compare Koru's label loops to Zig's while loops
echo "======================================"
echo "Generated Koru Code (output_emitted.zig)"
echo "======================================"
echo ""
if [ -f "output_emitted.zig" ]; then
echo "Looking for loop patterns..."
echo ""
echo "1. Label-based loop (should look like: loop_x: while (true) { ... continue :loop_x; })"
grep -A 10 "loop_.*: while" output_emitted.zig | head -15 || echo " (not found - may use different pattern)"
echo ""
echo "2. Dead loop (should be eliminated or very simple)"
grep -B 2 -A 5 "dead_loop\|dead.*while" output_emitted.zig | head -10 || echo " ✅ Dead loop eliminated (not found in output)"
echo ""
echo "3. Main function"
grep -A 20 "pub fn main" output_emitted.zig | head -25
else
echo "❌ output_emitted.zig not found"
echo " Run: koruc input.kz"
fi
echo ""
echo "======================================"
echo "Baseline Zig Code"
echo "======================================"
echo ""
cat baseline.zig
Expected output
Sum: 49999995000000Flows
flow ~count click a branch to expand · @labels scroll to their anchor
#loop count (i: 0, sum: 0)
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