diff --git a/lib/host/warm-conf.sh b/lib/host/warm-conf.sh index e239d5da..10e8e894 100755 --- a/lib/host/warm-conf.sh +++ b/lib/host/warm-conf.sh @@ -119,10 +119,31 @@ cmd_run() { if [ "$totf" -eq 0 ]; then echo "ok $totp passed (warm)"; else echo "FAIL $totp passed, $totf failed (warm)"; return 1; fi } +# profiling: eval an SX expression against the warm image, report round-trip time. The +# epoch protocol only accepts COMMANDS, so the expr is wrapped in (eval "") with +# quotes/backslashes escaped; errors come back as (error N …), success as (ok N …). +cmd_eval() { + if ! _running; then echo "warm: not running"; return 1; fi + local expr="$1" esc off e t0 t1 + esc="${expr//\\/\\\\}"; esc="${esc//\"/\\\"}" + off="$(wc -c < "$LOG")"; e="$(cat "$EPF")"; e=$((e+1)); echo "$e" > "$EPF" + t0=$(date +%s.%N) + { printf '(epoch %d)\n(eval "%s")\n' "$e" "$esc"; } > "$FIFO" + # an (eval …) acks as (ok-len N C) with the result printed on its own line(s); an error + # acks as (error N …). Wait for either, then show the result line (the non-ack output). + _wait_for "^\((ok-len|error) $e " "$off" 600 || { echo " (eval timeout)"; return 1; } + t1=$(date +%s.%N) + printf ' [%6.2fs] %s\n' "$(echo "$t1 - $t0" | bc -l)" "$(tail -c +"$((off+1))" "$LOG" | grep -vE '^\((ok|ok-len) ' | tail -1)" +} +# reload one or more module files into the warm image (e.g. after editing blog.sx). +cmd_reload() { if ! _running; then echo "warm: not running"; return 1; fi; shift; local last; last="$(_emit_loads "$@")"; _wait_for "^\(ok $last " 0 300 && echo "warm: reloaded $* (epoch $last)"; } + case "${1:-}" in start) cmd_start ;; stop) cmd_stop ;; restart) cmd_stop; cmd_start ;; run) shift; cmd_run "${1:-}" ;; - *) echo "usage: $0 {start|run [suite]|stop|restart}" >&2; exit 1 ;; + eval) cmd_eval "${2:-}" ;; + reload) cmd_reload "$@" ;; + *) echo "usage: $0 {start|run [suite]|stop|restart|eval |reload }" >&2; exit 1 ;; esac