#!/usr/bin/env bash # Erlang-on-SX ring benchmark. # # Spawns N processes in a ring, passes a token N hops (one full round), # and reports wall-clock time + throughput. Aspirational target from # the plan is 1M processes; current sync-scheduler architecture caps out # orders of magnitude lower — this script measures honestly across a # range of N so the result/scaling is recorded. # # Usage: # bash lib/erlang/bench_ring.sh # default ladder # bash lib/erlang/bench_ring.sh 100 1000 5000 # custom Ns set -uo pipefail cd "$(git rev-parse --show-toplevel)" SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}" if [ ! -x "$SX_SERVER" ]; then SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe" fi if [ ! -x "$SX_SERVER" ]; then echo "ERROR: sx_server.exe not found." >&2 exit 1 fi if [ "$#" -gt 0 ]; then NS=("$@") else NS=(10 100 500 1000) fi TMPFILE=$(mktemp) trap "rm -f $TMPFILE" EXIT # One-line Erlang program. Replaces __N__ with the size for each run. PROGRAM='Me = self(), N = __N__, Spawner = fun () -> receive {setup, Next} -> Loop = fun () -> receive {token, 0, Parent} -> Parent ! done; {token, K, Parent} -> Next ! {token, K-1, Parent}, Loop() end end, Loop() end end, BuildRing = fun (K, Acc) -> if K =:= 0 -> Acc; true -> BuildRing(K-1, [spawn(Spawner) | Acc]) end end, Pids = BuildRing(N, []), Wire = fun (Ps) -> case Ps of [P, Q | _] -> P ! {setup, Q}, Wire(tl(Ps)); [Last] -> Last ! {setup, hd(Pids)} end end, Wire(Pids), hd(Pids) ! {token, N, Me}, receive done -> done end' run_n() { local n="$1" local prog="${PROGRAM//__N__/$n}" cat > "$TMPFILE" <&1) end_s=$(date +%s) end_ns=$(date +%N) local ok="false" if echo "$out" | grep -q ':name "done"'; then ok="true"; fi # ms = (end_s - start_s)*1000 + (end_ns - start_ns)/1e6 elapsed_ms=$(awk -v s1="$start_s" -v n1="$start_ns" -v s2="$end_s" -v n2="$end_ns" \ 'BEGIN { printf "%d", (s2 - s1) * 1000 + (n2 - n1) / 1000000 }') if [ "$ok" = "true" ]; then local hops_per_s hops_per_s=$(awk -v n="$n" -v ms="$elapsed_ms" \ 'BEGIN { if (ms == 0) ms = 1; printf "%.0f", n * 1000 / ms }') printf " N=%-8s hops=%-8s %sms (%s hops/s)\n" "$n" "$n" "$elapsed_ms" "$hops_per_s" else printf " N=%-8s FAILED %sms\n" "$n" "$elapsed_ms" fi } echo "Ring benchmark — sx_server.exe (synchronous scheduler)" echo for n in "${NS[@]}"; do run_n "$n" done echo echo "Note: 1M-process target from the plan is aspirational; the synchronous" echo "scheduler with shift-based suspension and dict-based env copies is not" echo "engineered for that scale. Numbers above are honest baselines."