Files
next.orly.dev/cmd/benchmark/profile.sh
mleku 202d3171f9 Implement multi-platform build system with pure Go support
- Introduced a comprehensive build system that supports multiple platforms (Linux, macOS, Windows, Android) using pure Go builds (`CGO_ENABLED=0`).
- Updated all build and test scripts to ensure compatibility with the new purego approach, allowing for dynamic loading of `libsecp256k1` at runtime.
- Added detailed documentation on the build process, platform detection, and deployment options.
- Enhanced CI/CD workflows to automate builds for all supported platforms and include necessary libraries in releases.
- Updated `.gitignore` to exclude build output files.
- Created new documentation files for deployment and multi-platform build summaries.
2025-11-04 20:29:19 +00:00

168 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Runs the ORLY relay with CPU profiling enabled and opens the resulting
# pprof profile in a local web UI.
#
# Usage:
# ./profile.sh [duration_seconds]
#
# - Builds the relay.
# - Starts it with ORLY_PPROF=cpu and minimal logging.
# - Waits for the profile path printed at startup.
# - Runs for DURATION seconds (default 10), then stops the relay to flush the
# CPU profile to disk.
# - Launches `go tool pprof -http=:8000` for convenient browsing.
#
# Notes:
# - The profile file path is detected from the relay's stdout/stderr lines
# emitted by github.com/pkg/profile, typically like:
# profile: cpu profiling enabled, path: /tmp/profile123456/cpu.pprof
# - You can change DURATION by passing a number of seconds as the first arg
# or by setting DURATION env var.
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
cd "$REPO_ROOT"
DURATION="${1:-${DURATION:-10}}"
PPROF_HTTP_PORT="${PPROF_HTTP_PORT:-8000}"
# Load generation controls
LOAD_ENABLED="${LOAD_ENABLED:-1}" # set to 0 to disable load
# Use the benchmark main package in cmd/benchmark as the load generator
BENCHMARK_PKG_DIR="$REPO_ROOT/cmd/benchmark"
BENCHMARK_BIN="${BENCHMARK_BIN:-}" # if empty, we will build to $RUN_DIR/benchmark
BENCHMARK_EVENTS="${BENCHMARK_EVENTS:-}" # optional override for -events
BENCHMARK_DURATION="${BENCHMARK_DURATION:-}" # optional override for -duration (e.g. 30s); defaults to DURATION seconds
BIN="$REPO_ROOT/next.orly.dev"
LOG_DIR="${LOG_DIR:-$REPO_ROOT/cmd/benchmark/reports}"
mkdir -p "$LOG_DIR"
RUN_TS="$(date +%Y%m%d_%H%M%S)"
RUN_DIR="$LOG_DIR/profile_run_${RUN_TS}"
mkdir -p "$RUN_DIR"
LOG_FILE="$RUN_DIR/relay.log"
LOAD_LOG_FILE="$RUN_DIR/load.log"
echo "[profile.sh] Building relay binary (pure Go + purego)..."
CGO_ENABLED=0 go build -o "$BIN" .
# Copy libsecp256k1.so next to binary if available (runtime optional)
if [[ -f "pkg/crypto/p8k/libsecp256k1.so" ]]; then
cp pkg/crypto/p8k/libsecp256k1.so "$(dirname "$BIN")/"
fi
# Ensure we clean up the child process on exit
RELAY_PID=""
LOAD_PID=""
cleanup() {
if [[ -n "$LOAD_PID" ]] && kill -0 "$LOAD_PID" 2>/dev/null; then
echo "[profile.sh] Stopping load generator (pid=$LOAD_PID) ..."
kill -INT "$LOAD_PID" 2>/dev/null || true
sleep 0.5
kill -TERM "$LOAD_PID" 2>/dev/null || true
fi
if [[ -n "$RELAY_PID" ]] && kill -0 "$RELAY_PID" 2>/dev/null; then
echo "[profile.sh] Stopping relay (pid=$RELAY_PID) ..."
kill -INT "$RELAY_PID" 2>/dev/null || true
# give it a moment to exit and flush profile
sleep 1
kill -TERM "$RELAY_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
# Start the relay with CPU profiling enabled. Capture both stdout and stderr.
echo "[profile.sh] Starting relay with CPU profiling enabled ..."
(
ORLY_LOG_LEVEL=off \
ORLY_LISTEN="${ORLY_LISTEN:-127.0.0.1}" \
ORLY_PORT="${ORLY_PORT:-3334}" \
ORLY_PPROF=cpu \
"$BIN"
) >"$LOG_FILE" 2>&1 &
RELAY_PID=$!
echo "[profile.sh] Relay started with pid $RELAY_PID; logging to $LOG_FILE"
# Wait until the profile path is printed. Timeout after reasonable period.
PPROF_FILE=""
START_TIME=$(date +%s)
TIMEOUT=30
echo "[profile.sh] Waiting for profile path to appear in relay output ..."
while :; do
if grep -Eo "/tmp/profile[^ ]+/cpu\.pprof" "$LOG_FILE" >/dev/null 2>&1; then
PPROF_FILE=$(grep -Eo "/tmp/profile[^ ]+/cpu\.pprof" "$LOG_FILE" | tail -n1)
break
fi
NOW=$(date +%s)
if (( NOW - START_TIME > TIMEOUT )); then
echo "[profile.sh] ERROR: Timed out waiting for profile path in $LOG_FILE" >&2
echo "Last 50 log lines:" >&2
tail -n 50 "$LOG_FILE" >&2
exit 1
fi
sleep 0.3
done
echo "[profile.sh] Detected profile file: $PPROF_FILE"
# Optionally start load generator to exercise the relay
if [[ "$LOAD_ENABLED" == "1" ]]; then
# Build benchmark binary if not provided
if [[ -z "$BENCHMARK_BIN" ]]; then
BENCHMARK_BIN="$RUN_DIR/benchmark"
echo "[profile.sh] Building benchmark load generator (pure Go + purego) ($BENCHMARK_PKG_DIR) ..."
cd "$BENCHMARK_PKG_DIR"
CGO_ENABLED=0 go build -o "$BENCHMARK_BIN" .
# Copy libsecp256k1.so if available (runtime optional)
if [[ -f "$REPO_ROOT/pkg/crypto/p8k/libsecp256k1.so" ]]; then
cp "$REPO_ROOT/pkg/crypto/p8k/libsecp256k1.so" "$RUN_DIR/"
fi
cd "$REPO_ROOT"
fi
BENCH_DB_DIR="$RUN_DIR/benchdb"
mkdir -p "$BENCH_DB_DIR"
DURATION_ARG="${BENCHMARK_DURATION:-${DURATION}s}"
EXTRA_EVENTS=""
if [[ -n "$BENCHMARK_EVENTS" ]]; then
EXTRA_EVENTS="-events=$BENCHMARK_EVENTS"
fi
echo "[profile.sh] Starting benchmark load generator for duration $DURATION_ARG ..."
RELAY_URL="ws://${ORLY_LISTEN:-127.0.0.1}:${ORLY_PORT:-3334}"
echo "[profile.sh] Using relay URL: $RELAY_URL"
(
"$BENCHMARK_BIN" -relay-url="$RELAY_URL" -net-workers="${NET_WORKERS:-2}" -net-rate="${NET_RATE:-20}" -duration="$DURATION_ARG" $EXTRA_EVENTS \
>"$LOAD_LOG_FILE" 2>&1 &
)
LOAD_PID=$!
echo "[profile.sh] Load generator started (pid=$LOAD_PID); logging to $LOAD_LOG_FILE"
else
echo "[profile.sh] LOAD_ENABLED=0; not starting load generator."
fi
echo "[profile.sh] Letting the relay run for ${DURATION}s to collect CPU samples ..."
sleep "$DURATION"
# Stop the relay to flush the CPU profile
cleanup
# Disable trap so we don't double-kill
trap - EXIT
# Wait briefly to ensure the profile file is finalized
for i in {1..20}; do
if [[ -s "$PPROF_FILE" ]]; then
break
fi
sleep 0.2
done
if [[ ! -s "$PPROF_FILE" ]]; then
echo "[profile.sh] WARNING: Profile file exists but is empty or missing: $PPROF_FILE" >&2
fi
# Launch pprof HTTP UI
echo "[profile.sh] Launching pprof web UI (http://localhost:${PPROF_HTTP_PORT}) ..."
exec go tool pprof -http=":${PPROF_HTTP_PORT}" "$BIN" "$PPROF_FILE"