feat: HTTP registry, app/bench harnesses, and DWARF #line maps
Ship QUALITY_PLAN sessions 31–33: fetchable package index URLs, showcase app and micro/nexus benchmarks, and debugger-friendly C codegen. - Registry: BUX_REGISTRY accepts http(s) URLs (curl/wget → ~/.bux/cache) - E.2: make test-apps smoke for nexus/boko/simpledb/jwt-pitbul - E.5: benches/micro + C/Nim/Zig twins; make bench-nexus (wrk) - E.4: HIR locs → #line .bux; default -O0 -g; --release -O2; make test-dwarf
This commit is contained in:
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run Bux micro-benchmarks + language twins (C / Nim / optional Zig). E.5
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
RUN_NEXUS="${BENCH_NEXUS:-0}"
|
||||
|
||||
if [[ ! -x "$BUXC" ]]; then
|
||||
(cd "$ROOT" && make build >/dev/null)
|
||||
fi
|
||||
|
||||
echo "=== build benches/micro ==="
|
||||
(cd "$ROOT/benches/micro" && "$BUXC" build)
|
||||
|
||||
echo ""
|
||||
echo "--- Bux ---"
|
||||
"$ROOT/benches/micro/build/micro"
|
||||
|
||||
echo ""
|
||||
echo "--- C reference (gcc -O2) ---"
|
||||
mkdir -p "$ROOT/benches/c/build"
|
||||
gcc -O2 -o "$ROOT/benches/c/build/fib" "$ROOT/benches/c/fib.c"
|
||||
gcc -O2 -o "$ROOT/benches/c/build/int_loop" "$ROOT/benches/c/int_loop.c"
|
||||
echo -n "C "; "$ROOT/benches/c/build/fib"
|
||||
echo -n "C "; "$ROOT/benches/c/build/int_loop"
|
||||
|
||||
echo ""
|
||||
echo "--- Nim reference (-d:release) ---"
|
||||
if command -v nim >/dev/null 2>&1; then
|
||||
mkdir -p "$ROOT/benches/nim/build"
|
||||
nim c -d:release --opt:speed --hints:off --warnings:off \
|
||||
-o:"$ROOT/benches/nim/build/fib" \
|
||||
"$ROOT/benches/nim/fib.nim" >/dev/null 2>&1
|
||||
nim c -d:release --opt:speed --hints:off --warnings:off \
|
||||
-o:"$ROOT/benches/nim/build/int_loop" \
|
||||
"$ROOT/benches/nim/int_loop.nim" >/dev/null 2>&1
|
||||
echo -n "Nim "; "$ROOT/benches/nim/build/fib"
|
||||
echo -n "Nim "; "$ROOT/benches/nim/build/int_loop"
|
||||
else
|
||||
echo "(nim not installed — skip)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Zig reference (-OReleaseFast) ---"
|
||||
if command -v zig >/dev/null 2>&1; then
|
||||
mkdir -p "$ROOT/benches/zig/build"
|
||||
(cd "$ROOT/benches/zig" && zig build-exe -OReleaseFast -femit-bin=build/fib fib.zig 2>/dev/null)
|
||||
(cd "$ROOT/benches/zig" && zig build-exe -OReleaseFast -femit-bin=build/int_loop int_loop.zig 2>/dev/null)
|
||||
echo -n "Zig "; "$ROOT/benches/zig/build/fib"
|
||||
echo -n "Zig "; "$ROOT/benches/zig/build/int_loop"
|
||||
else
|
||||
echo "(zig not installed — skip; sources in benches/zig/)"
|
||||
fi
|
||||
|
||||
if [[ "$RUN_NEXUS" == "1" ]]; then
|
||||
echo ""
|
||||
echo "=== Nexus throughput (BENCH_NEXUS=1) ==="
|
||||
chmod +x "$ROOT/tools/bench_nexus.sh"
|
||||
"$ROOT/tools/bench_nexus.sh"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [[ "$RUN_NEXUS" == "1" ]]; then
|
||||
echo "PASS: bench (Bux + language twins + nexus)"
|
||||
else
|
||||
echo "PASS: bench (Bux + language twins)"
|
||||
fi
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# Nexus HTTP throughput bench (E.5) — wrk against /api/health
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
NEXUS_DIR="$ROOT/apps/nexus"
|
||||
PORT="${NEXUS_PORT:-18080}"
|
||||
DURATION="${NEXUS_BENCH_DURATION:-5s}"
|
||||
CONNECTIONS="${NEXUS_BENCH_C:-64}"
|
||||
THREADS="${NEXUS_BENCH_T:-4}"
|
||||
WORKERS="${NEXUS_WORKERS:-4}"
|
||||
|
||||
if [[ ! -x "$BUXC" ]]; then
|
||||
(cd "$ROOT" && make build >/dev/null)
|
||||
fi
|
||||
|
||||
if ! command -v wrk >/dev/null 2>&1; then
|
||||
echo "error: wrk not found (apt install wrk / package manager)" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v curl >/dev/null 2>&1; then
|
||||
echo "error: curl required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== build nexus ==="
|
||||
(cd "$NEXUS_DIR" && "$BUXC" build)
|
||||
|
||||
# Free port if something leftover
|
||||
if command -v fuser >/dev/null 2>&1; then
|
||||
fuser -k "${PORT}/tcp" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
export NEXUS_PORT="$PORT"
|
||||
export NEXUS_BIND="127.0.0.1"
|
||||
export NEXUS_WORKERS="$WORKERS"
|
||||
export NEXUS_PUBLIC="$NEXUS_DIR/public"
|
||||
|
||||
PID=""
|
||||
cleanup() {
|
||||
if [[ -n "$PID" ]]; then
|
||||
kill "$PID" 2>/dev/null || true
|
||||
wait "$PID" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=== start nexus :${PORT} (workers=${WORKERS}) ==="
|
||||
(
|
||||
cd "$NEXUS_DIR"
|
||||
./build/nexus
|
||||
) >"$ROOT/benches/nexus_run.log" 2>&1 &
|
||||
PID=$!
|
||||
|
||||
URL="http://127.0.0.1:${PORT}/api/health"
|
||||
ready=0
|
||||
for _ in $(seq 1 50); do
|
||||
if curl -fsS "$URL" >/dev/null 2>&1; then
|
||||
ready=1
|
||||
break
|
||||
fi
|
||||
if ! kill -0 "$PID" 2>/dev/null; then
|
||||
echo "error: nexus exited early; log:" >&2
|
||||
cat "$ROOT/benches/nexus_run.log" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
if [[ "$ready" -ne 1 ]]; then
|
||||
echo "error: nexus did not become ready on $URL" >&2
|
||||
cat "$ROOT/benches/nexus_run.log" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== curl sanity ==="
|
||||
curl -fsS "$URL"
|
||||
echo ""
|
||||
|
||||
echo "=== wrk -t${THREADS} -c${CONNECTIONS} -d${DURATION} ${URL} ==="
|
||||
wrk -t"$THREADS" -c"$CONNECTIONS" -d"$DURATION" --latency "$URL" | tee "$ROOT/benches/nexus_wrk.out"
|
||||
|
||||
# Parse a compact summary line if possible
|
||||
if grep -q "Requests/sec" "$ROOT/benches/nexus_wrk.out"; then
|
||||
rps=$(grep "Requests/sec" "$ROOT/benches/nexus_wrk.out" | awk '{print $2}')
|
||||
echo "BENCH nexus_health rps=${rps} port=${PORT} workers=${WORKERS} c=${CONNECTIONS} t=${THREADS} d=${DURATION}"
|
||||
fi
|
||||
|
||||
echo "PASS: nexus throughput bench"
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke: build showcase apps (E.2) and run non-server CLIs.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
|
||||
if [[ ! -x "$BUXC" ]]; then
|
||||
(cd "$ROOT" && make build >/dev/null)
|
||||
fi
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
APPS=(simpledb jwt-pitbul nexus boko-framework)
|
||||
for app in "${APPS[@]}"; do
|
||||
echo "=== build apps/$app ==="
|
||||
(cd "$ROOT/apps/$app" && "$BUXC" build)
|
||||
test -x "$ROOT/apps/$app/build/$app" || test -x "$ROOT/apps/$app/build/${app}" || {
|
||||
# binary name may match package Name in bux.toml
|
||||
ls "$ROOT/apps/$app/build/"
|
||||
}
|
||||
done
|
||||
|
||||
echo "=== simpledb set/get/del ==="
|
||||
DB="$TMP/test.db"
|
||||
SDB="$ROOT/apps/simpledb/build/simpledb"
|
||||
"$SDB" "$DB" set name Bux
|
||||
"$SDB" "$DB" set version 0.5
|
||||
out=$("$SDB" "$DB" get name)
|
||||
echo "$out" | grep -q Bux
|
||||
"$SDB" "$DB" has name | grep -q true
|
||||
"$SDB" "$DB" count | grep -q 2
|
||||
"$SDB" "$DB" del version
|
||||
"$SDB" "$DB" count | grep -q 1
|
||||
|
||||
echo "=== jwt-pitbul sign/verify/decode ==="
|
||||
JWT="$ROOT/apps/jwt-pitbul/build/jwt-pitbul"
|
||||
token=$("$JWT" sign HS256 'smoke-secret' '{"sub":"bux","role":"test"}')
|
||||
echo "token=${token:0:40}..."
|
||||
"$JWT" verify "$token" HS256 'smoke-secret' | tee "$TMP/jwt_verify.out"
|
||||
grep -qiE 'valid|Signature|sub' "$TMP/jwt_verify.out" || true
|
||||
# decode always works without key
|
||||
"$JWT" decode "$token" | tee "$TMP/jwt_decode.out"
|
||||
grep -q sub "$TMP/jwt_decode.out" || grep -q '"sub"' "$TMP/jwt_decode.out"
|
||||
|
||||
echo "=== nexus/boko binaries exist ==="
|
||||
test -x "$ROOT/apps/nexus/build/nexus"
|
||||
test -x "$ROOT/apps/boko-framework/build/boko-framework"
|
||||
|
||||
echo "PASS: apps smoke (build 4 + simpledb + jwt-pitbul)"
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke: DWARF / #line maps for debugger (E.4)
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
|
||||
if [[ ! -x "$BUXC" ]]; then
|
||||
(cd "$ROOT" && make build >/dev/null)
|
||||
fi
|
||||
|
||||
PKG="$ROOT/examples_pkg/hello"
|
||||
mkdir -p "$PKG/src"
|
||||
cp "$ROOT/examples/hello.bux" "$PKG/src/Main.bux"
|
||||
if [[ ! -f "$PKG/bux.toml" ]]; then
|
||||
cat > "$PKG/bux.toml" <<'EOF'
|
||||
[Package]
|
||||
Name = "hello"
|
||||
Version = "0.1.0"
|
||||
Type = "bin"
|
||||
|
||||
[Build]
|
||||
Output = "Bin"
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "=== debug build (default -O0 -g + #line) ==="
|
||||
"$BUXC" build "$PKG"
|
||||
MAIN_C="$PKG/build/main.c"
|
||||
BIN="$PKG/build/hello"
|
||||
test -f "$MAIN_C"
|
||||
test -x "$BIN"
|
||||
|
||||
# Expect #line pointing at .bux sources (user or stdlib)
|
||||
if ! grep -qE '^#line [0-9]+ ".*\.bux"' "$MAIN_C"; then
|
||||
echo "error: no #line …\".bux\" directives in $MAIN_C" >&2
|
||||
grep -n '#line' "$MAIN_C" | sed -n '1,5p' || true
|
||||
exit 1
|
||||
fi
|
||||
echo " #line maps present:"
|
||||
grep -E '^#line [0-9]+ ".*\.bux"' "$MAIN_C" | sed -n '1,5p' || true
|
||||
# User Main should map back to the package Main.bux
|
||||
if ! grep -qE '^#line [0-9]+ ".*Main\.bux"' "$MAIN_C"; then
|
||||
echo "error: no #line for user Main.bux" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " user Main.bux #line present"
|
||||
|
||||
# DWARF sections
|
||||
if command -v readelf >/dev/null 2>&1; then
|
||||
if ! readelf -S "$BIN" | grep -q '\.debug_info'; then
|
||||
echo "error: no .debug_info in $BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " .debug_info present"
|
||||
if readelf -p .debug_str "$BIN" 2>/dev/null | grep -q '\.bux'; then
|
||||
echo " .debug_str contains .bux paths"
|
||||
else
|
||||
echo " (note: .debug_str may omit .bux; line tables still OK)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# gdb: list Main
|
||||
if command -v gdb >/dev/null 2>&1; then
|
||||
echo "=== gdb list Main ==="
|
||||
set +e
|
||||
gdb -batch -ex "file $BIN" -ex "list Main" 2>/dev/null | sed -n '1,20p'
|
||||
set -e
|
||||
fi
|
||||
|
||||
echo "=== release build (no #line, no -g required) ==="
|
||||
"$BUXC" build --release "$PKG"
|
||||
if grep -qE '^#line ' "$MAIN_C"; then
|
||||
echo "error: release build still has #line" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " release: no #line (OK)"
|
||||
if command -v readelf >/dev/null 2>&1; then
|
||||
if readelf -S "$BIN" | grep -q '\.debug_info'; then
|
||||
echo " (release still has debug sections — unexpected but non-fatal)"
|
||||
else
|
||||
echo " release: no .debug_info (OK)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rebuild debug so leftover state is debug-friendly for other tests
|
||||
"$BUXC" build "$PKG" >/dev/null
|
||||
|
||||
echo "PASS: dwarf smoke (#line + .debug_info + --release)"
|
||||
+48
-3
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke: registry search + add + install + build with greet package (E.1)
|
||||
# Also verifies HTTP-fetchable registry index (E.1b).
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
BUXC="$ROOT/buxc"
|
||||
@@ -10,9 +11,17 @@ if [[ ! -x "$BUXC" ]]; then
|
||||
fi
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
HTTP_PID=""
|
||||
cleanup() {
|
||||
if [[ -n "$HTTP_PID" ]]; then
|
||||
kill "$HTTP_PID" 2>/dev/null || true
|
||||
wait "$HTTP_PID" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
echo "=== bux search greet ==="
|
||||
echo "=== bux search greet (local file) ==="
|
||||
"$BUXC" search greet | tee "$TMP/search.out"
|
||||
grep -q greet "$TMP/search.out"
|
||||
|
||||
@@ -61,4 +70,40 @@ echo "=== bux run ==="
|
||||
"$BUXC" run . | tee "$TMP/run.out"
|
||||
grep -q "Hello, Bux!" "$TMP/run.out"
|
||||
|
||||
echo "PASS: registry smoke (search + add + install + build)"
|
||||
# --- HTTP registry index ---
|
||||
echo "=== HTTP registry index (E.1b) ==="
|
||||
mkdir -p "$TMP/http"
|
||||
# Absolute file: path so resolution works after download to ~/.bux/cache
|
||||
cat > "$TMP/http/registry.toml" <<EOF
|
||||
[[package]]
|
||||
name = "greet"
|
||||
version = "0.1.1"
|
||||
source = "file:$ROOT/registry/packages/greet"
|
||||
description = "HTTP-served greet package"
|
||||
EOF
|
||||
|
||||
# Free port via python
|
||||
PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')
|
||||
(
|
||||
cd "$TMP/http"
|
||||
python3 -m http.server "$PORT" --bind 127.0.0.1 >/dev/null 2>&1
|
||||
) &
|
||||
HTTP_PID=$!
|
||||
# Wait until server responds
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if curl -fsS "http://127.0.0.1:${PORT}/registry.toml" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
export BUX_REGISTRY="http://127.0.0.1:${PORT}/registry.toml"
|
||||
export BUX_REGISTRY_REFRESH=1
|
||||
"$BUXC" search greet | tee "$TMP/http_search.out"
|
||||
grep -q greet "$TMP/http_search.out"
|
||||
grep -q "http://127.0.0.1" "$TMP/http_search.out" || grep -q "cached" "$TMP/http_search.out"
|
||||
unset BUX_REGISTRY_REFRESH
|
||||
# Second search should hit cache without refresh
|
||||
"$BUXC" search greet | grep -q greet
|
||||
|
||||
echo "PASS: registry smoke (local + HTTP search + add + install + build)"
|
||||
|
||||
Reference in New Issue
Block a user