Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Iabd307b475f6568cff4d1ae6e5ae56ef6a6a6964
158 lines
4.6 KiB
Bash
Executable file
158 lines
4.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
echo "# Running benchmarks..."
|
|
echo ""
|
|
|
|
BENCH_DIR="$(pwd)/tests/benchmark"
|
|
IRC_BIN="$(pwd)/build/nix-irc"
|
|
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
YELLOW='\033[0;33m'
|
|
NC='\033[0m'
|
|
|
|
get_ms() {
|
|
local time_str="$1"
|
|
if [[ $time_str =~ ([0-9]+)m([0-9.]+)s ]]; then
|
|
local mins="${BASH_REMATCH[1]}"
|
|
local secs="${BASH_REMATCH[2]}"
|
|
local ms
|
|
ms=$(awk "BEGIN {printf \"%.1f\", ($mins * 60000) + ($secs * 1000)}")
|
|
echo "$ms"
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
run_benchmark() {
|
|
local name="$1"
|
|
local file="$2"
|
|
|
|
echo -e "${BLUE}=== $name ===${NC}"
|
|
echo ""
|
|
|
|
# Measure compilation time only
|
|
echo -n " Compilation only: "
|
|
local compile_start
|
|
compile_start=$(date +%s%N)
|
|
"$IRC_BIN" "$file" /tmp/bench.nixir >/dev/null 2>&1
|
|
local compile_end
|
|
compile_end=$(date +%s%N)
|
|
local compile_ms=$(((compile_end - compile_start) / 1000000))
|
|
echo -e "${YELLOW}${compile_ms}ms${NC}"
|
|
|
|
# Measure IR loading only (deserialization + evaluation)
|
|
echo -n " IR load only: "
|
|
PLUGIN_PATH="$(pwd)/build/nix-ir-plugin.so"
|
|
if [ ! -f "$PLUGIN_PATH" ]; then
|
|
echo -e "${YELLOW}skipped${NC} (plugin not built)"
|
|
else
|
|
# Pre-compile the IR
|
|
"$IRC_BIN" "$file" /tmp/bench.nixir >/dev/null 2>&1
|
|
|
|
# Measure just the loading (average of 10 runs to reduce noise)
|
|
local total_load_us=0
|
|
for _ in {1..10}; do
|
|
local load_output
|
|
load_output=$(nix-instantiate --plugin-files "$PLUGIN_PATH" --eval --expr "builtins.nixIR_loadIR \"/tmp/bench.nixir\"" 2>&1 >/dev/null | grep "nixIR timing" | grep -oP 'total=\K[0-9]+')
|
|
total_load_us=$((total_load_us + load_output))
|
|
done
|
|
local avg_load_us=$((total_load_us / 10))
|
|
local avg_load_ms_frac=$(awk "BEGIN {printf \"%.3f\", $avg_load_us / 1000}")
|
|
echo -e "${GREEN}${avg_load_ms_frac}ms${NC} avg (10 runs)"
|
|
fi
|
|
|
|
# Measure full pipeline (compile + nix-instantiate overhead + IR load)
|
|
echo -n " Full pipeline: "
|
|
if [ ! -f "$PLUGIN_PATH" ]; then
|
|
echo -e "${YELLOW}skipped${NC}"
|
|
else
|
|
local pipeline_start
|
|
pipeline_start=$(date +%s%N)
|
|
"$IRC_BIN" "$file" /tmp/bench.nixir >/dev/null 2>&1
|
|
nix-instantiate --plugin-files "$PLUGIN_PATH" --eval --expr "builtins.nixIR_loadIR \"/tmp/bench.nixir\"" >/dev/null 2>&1
|
|
local pipeline_end
|
|
pipeline_end=$(date +%s%N)
|
|
local pipeline_ms=$(((pipeline_end - pipeline_start) / 1000000))
|
|
echo -e "${YELLOW}${pipeline_ms}ms${NC}"
|
|
fi
|
|
|
|
# Source and IR sizes
|
|
local src_size
|
|
src_size=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null)
|
|
local ir_size
|
|
ir_size=$(stat -c%s /tmp/bench.nixir 2>/dev/null || stat -f%z /tmp/bench.nixir 2>/dev/null)
|
|
local ratio=0
|
|
if [[ "$src_size" -gt 0 ]]; then
|
|
ratio=$((ir_size * 100 / src_size))
|
|
fi
|
|
echo -e " Source size: ${src_size}B"
|
|
echo -e " IR bundle size: ${ir_size}B (${ratio}% of source)"
|
|
|
|
echo ""
|
|
|
|
# Native Nix evaluation (baseline)
|
|
echo -n " Native Nix eval: "
|
|
local native_total=0
|
|
for _ in {1..5}; do
|
|
local t
|
|
t=$( (time nix-instantiate --eval --strict "$file" >/dev/null 2>&1) 2>&1 | grep "real" | awk '{print $2}')
|
|
local ms
|
|
ms=$(get_ms "$t")
|
|
native_total=$(awk "BEGIN {print $native_total + $ms}")
|
|
done
|
|
local native_avg
|
|
native_avg=$(awk "BEGIN {printf \"%.1f\", $native_total / 5}")
|
|
echo -e "${GREEN}${native_avg}ms${NC} avg (5 runs)"
|
|
|
|
echo ""
|
|
}
|
|
|
|
echo "Measuring IR compilation speed and bundle size characteristics."
|
|
echo ""
|
|
|
|
run_benchmark "Simple Expression" "$BENCH_DIR/simple.nix"
|
|
run_benchmark "Medium Complexity" "$BENCH_DIR/medium.nix"
|
|
run_benchmark "Large Expression" "$BENCH_DIR/large.nix"
|
|
|
|
# Overall statistics
|
|
echo -e "${BLUE}=== Overall Statistics ===${NC}"
|
|
echo ""
|
|
|
|
testdir=$(mktemp -d)
|
|
total_nix=0
|
|
total_ir=0
|
|
total_compile_time=0
|
|
|
|
for f in "$BENCH_DIR"/*.nix; do
|
|
nixsize=$(stat -c%s "$f" 2>/dev/null || stat -f%z "$f" 2>/dev/null)
|
|
base=$(basename "$f" .nix)
|
|
irfile="${testdir}/${base}.nixir"
|
|
|
|
start=$(date +%s%N)
|
|
"$IRC_BIN" "$f" "$irfile" >/dev/null 2>&1
|
|
end=$(date +%s%N)
|
|
compile_time=$(((end - start) / 1000000))
|
|
|
|
if [ -f "$irfile" ]; then
|
|
irsize=$(stat -c%s "$irfile" 2>/dev/null || stat -f%z "$irfile" 2>/dev/null)
|
|
total_nix=$((total_nix + nixsize))
|
|
total_ir=$((total_ir + irsize))
|
|
total_compile_time=$((total_compile_time + compile_time))
|
|
fi
|
|
done
|
|
|
|
total_ratio=$((total_ir * 100 / total_nix))
|
|
avg_compile_time=$((total_compile_time / 3))
|
|
|
|
# TBH those are entirely unnecessary. However, I'm a sucker for data
|
|
# and those are trivial to compile. Might as well. Who knows, maybe it'll
|
|
# come in handy in the future.
|
|
echo " Total source size: ${total_nix}B"
|
|
echo " Total IR size: ${total_ir}B"
|
|
echo " Compression ratio: ${total_ratio}% of source"
|
|
echo " Average compile time: ${avg_compile_time}ms"
|
|
echo ""
|
|
|
|
rm -rf "$testdir"
|