#!/usr/bin/env bash # # Run all secp256k1 benchmarks. # Run from the amethyst root directory: # # ./quartz/benchmarks/run_all.sh # # Runs: C native, Kotlin/Native, JVM (always), and Android (if device connected). # set -uo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)" BENCH_DIR="$ROOT/quartz/benchmarks" # ============================================================================ # Platform detection # ============================================================================ OS_NAME="$(uname -s)" ARCH="$(uname -m)" case "$OS_NAME" in Linux) SO_NAME="libsecp256k1-jni.so" JAR_PLATFORM="linux" case "$ARCH" in aarch64|arm64) SO_PATH_PATTERN="*linux-aarch64*" ;; *) SO_PATH_PATTERN="*linux-x86_64*" ;; esac ;; Darwin) SO_NAME="libsecp256k1-jni.dylib" JAR_PLATFORM="darwin" SO_PATH_PATTERN="*darwin*" ;; *) echo "Unsupported OS: $OS_NAME" exit 1 ;; esac # ============================================================================ # 1. C native benchmark # ============================================================================ echo "=== Building C native benchmark ===" SO_PATH=$(find "$HOME/.gradle" -path "*/secp256k1-kmp-jni-jvm-${JAR_PLATFORM}*" -name "*.jar" 2>/dev/null | head -1) if [ -z "$SO_PATH" ]; then echo "ACINQ secp256k1-kmp-jni-jvm-${JAR_PLATFORM} JAR not found in Gradle cache." echo "Run './gradlew :quartz:jvmTest --tests *.Secp256k1Test' first to download it." exit 1 fi WORK=$(mktemp -d) (cd "$WORK" && jar xf "$SO_PATH") 2>/dev/null || true SO_FILE=$(find "$WORK" -name "$SO_NAME" -path "$SO_PATH_PATTERN" 2>/dev/null | head -1) if [ -z "$SO_FILE" ]; then echo "Could not find $SO_NAME for $OS_NAME-$ARCH in JAR." exit 1 fi cp "$SO_FILE" "$WORK/" # On macOS the dylib's LC_ID_DYLIB (install name) is a relative path like # "build/darwin/libsecp256k1-jni.dylib". dyld resolves it literally, ignoring # -rpath, so the binary fails at launch. Rewrite the install name to use # @rpath so the -Wl,-rpath we pass to gcc actually works. if [ "$OS_NAME" = "Darwin" ]; then install_name_tool -id "@rpath/$SO_NAME" "$WORK/$SO_NAME" 2>/dev/null || true fi if ! gcc -O2 -o "$WORK/bench" "$BENCH_DIR/secp256k1_native_bench.c" \ -L"$WORK" -lsecp256k1-jni -Wl,-rpath,"$WORK" 2>&1; then echo "gcc compilation failed" fi echo "=== Running C native benchmark ===" if [ -f "$WORK/bench" ]; then "$WORK/bench" 2>&1 else echo "(skipped — compilation failed)" fi echo "" # ============================================================================ # 2. Kotlin/Native benchmark (Linux and macOS) # ============================================================================ echo "=== Running Kotlin/Native benchmark ===" case "$OS_NAME" in Linux) KN_TARGET="linuxX64Test" ;; Darwin) KN_TARGET="macosArm64Test" ;; esac "$ROOT/gradlew" -p "$ROOT" ":quartz:$KN_TARGET" --tests "*.Secp256k1NativeBenchmark" \ 2>/dev/null || true KN_XML="$ROOT/quartz/build/test-results/$KN_TARGET/TEST-${KN_TARGET}.com.vitorpamplona.quartz.utils.secp256k1.Secp256k1NativeBenchmark.xml" if [ -f "$KN_XML" ]; then sed -n '//p' "$KN_XML" | grep -v 'CDATA\|]]>' else echo "K/Native benchmark XML not found." fi echo "" # ============================================================================ # 3. JVM benchmark # ============================================================================ echo "=== Running JVM benchmark ===" "$ROOT/gradlew" -p "$ROOT" :quartz:jvmTest --tests "*.Secp256k1Benchmark" \ 2>/dev/null || true JVM_XML="$ROOT/quartz/build/test-results/jvmTest/TEST-com.vitorpamplona.quartz.utils.secp256k1.Secp256k1Benchmark.xml" if [ -f "$JVM_XML" ]; then sed -n '//p' "$JVM_XML" | grep -v 'CDATA\|]]>' else echo "JVM benchmark XML not found." fi echo "" # ============================================================================ # 4. Android benchmark (if device/emulator connected) # ============================================================================ if command -v adb &>/dev/null && adb devices 2>/dev/null | grep -q "device$"; then echo "=== Running Android benchmark (device detected) ===" # Record start time so we can find results generated by this run. ANDROID_STAMP="$WORK/.android_stamp" touch "$ANDROID_STAMP" "$ROOT/gradlew" -p "$ROOT" :benchmark:connectedBenchmarkAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.class=com.vitorpamplona.quartz.benchmark.Secp256k1Benchmark \ 2>/dev/null || true FOUND=false # 1. Test-results XML (contains benchmark data in CDATA, like JVM results) ANDROID_XML=$(find "$ROOT/benchmark/build" \ \( -path "*test-results*" -o -path "*androidTest-results*" \) \ -name "*.xml" -newer "$ANDROID_STAMP" 2>/dev/null | head -1) if [ -n "$ANDROID_XML" ] && [ -f "$ANDROID_XML" ]; then sed -n '//p' "$ANDROID_XML" | grep -v 'CDATA\|]]>' FOUND=true fi # 2. Pulled benchmark JSON (AndroidX Benchmark writes here via Gradle) if [ "$FOUND" = false ]; then BENCH_JSON=$(find "$ROOT/benchmark/build/outputs" \ -path "*connected_android_test_additional_output*" \ -name "*.json" -newer "$ANDROID_STAMP" 2>/dev/null | head -1) if [ -n "$BENCH_JSON" ] && [ -f "$BENCH_JSON" ]; then cat "$BENCH_JSON" FOUND=true fi fi # 3. On-device benchmark JSON (legacy / older AndroidX Benchmark versions) if [ "$FOUND" = false ]; then BENCH_JSON=$(adb shell "ls /sdcard/Download/*benchmark*json 2>/dev/null" 2>/dev/null | head -1 | tr -d '\r') if [ -n "$BENCH_JSON" ]; then adb shell "cat '$BENCH_JSON'" 2>/dev/null FOUND=true fi fi if [ "$FOUND" = false ]; then echo "Android benchmark ran but results not found." fi echo "" else echo "=== Skipping Android benchmark (no device/emulator connected) ===" echo "" fi