This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

at master 7.8 kB View raw
1#!/usr/bin/env bash 2# 3# Drives one closed-loop experiment run for the model comparison harness: 4# 5# 1. Snapshots existing experiment logs on the phone (so we know which file 6# is the "new" one this run produces). 7# 2. Prompts you to confirm Experiment Mode is armed and Start has been 8# tapped on the phone (skipped with --no-confirm). 9# 3. Records t0_wall_ms in milliseconds, then plays the test video from the 10# start in QuickTime Player via osascript. 11# 4. Sleeps for --duration seconds. 12# 5. Pauses QuickTime. 13# 6. Prompts you to tap Stop on the phone (skipped with --no-confirm). 14# 7. Diffs the post-run file list against the snapshot, pulls only the 15# newly-written JSON file(s) into experiments/<run-id>/. 16# 8. Writes experiments/<run-id>/manifest.json with t0_wall_ms, the video 17# path, model tag, device info, and duration. 18# 19# Usage: 20# tools/run_experiment.sh \ 21# --video /abs/or/rel/path/test.mp4 \ 22# --duration 10 \ 23# --model-tag yolo11n_su_416 \ 24# [--device RFCX10EM9LR] \ 25# [--no-confirm] 26# 27# After two runs (model A then model B against the same video) point 28# tools/compare_logs.py at experiments/ to produce the report. 29 30set -euo pipefail 31 32ADB="${ADB:-/Users/virtualintern/Library/Android/sdk/platform-tools/adb}" 33# DEVICE may be passed via --device or EXP_DEVICE. Empty means "auto-detect: 34# if exactly one device is connected, use it; otherwise error and require 35# explicit --device". 36DEVICE="${EXP_DEVICE:-}" 37PKG="com.nate.posedetection.androidApp" 38REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" 39EXPERIMENTS_DIR="$REPO_ROOT/experiments" 40REMOTE_LOGS_DIR="/sdcard/Android/data/$PKG/files/experiment_logs" 41 42usage() { 43 sed -n '3,28p' "$0" 44 exit "${1:-1}" 45} 46 47VIDEO="" 48DURATION="" 49MODEL_TAG="" 50NO_CONFIRM=0 51 52while [ $# -gt 0 ]; do 53 case "$1" in 54 --video) VIDEO="$2"; shift 2 ;; 55 --duration) DURATION="$2"; shift 2 ;; 56 --model-tag) MODEL_TAG="$2"; shift 2 ;; 57 --device) DEVICE="$2"; shift 2 ;; 58 --no-confirm) NO_CONFIRM=1; shift ;; 59 -h|--help) usage 0 ;; 60 *) echo "unknown arg: $1" >&2; usage ;; 61 esac 62done 63 64[ -n "$VIDEO" ] || { echo "error: --video is required" >&2; exit 2; } 65[ -n "$DURATION" ] || { echo "error: --duration is required" >&2; exit 2; } 66[ -n "$MODEL_TAG" ] || { echo "error: --model-tag is required" >&2; exit 2; } 67 68if [ ! -f "$VIDEO" ]; then 69 echo "error: video file not found: $VIDEO" >&2 70 exit 2 71fi 72VIDEO_ABS="$(cd "$(dirname "$VIDEO")" && pwd)/$(basename "$VIDEO")" 73 74# Sanitize model tag for filesystem use (run-id slug). 75SAFE_TAG="$(printf '%s' "$MODEL_TAG" | tr -c 'A-Za-z0-9._-' '_' | sed 's/^_*//; s/_*$//')" 76[ -n "$SAFE_TAG" ] || SAFE_TAG="unnamed" 77 78# Resolve / verify device. 79if [ -z "$DEVICE" ]; then 80 # Auto-detect: only succeed if exactly one device is attached. 81 CONNECTED="$("$ADB" devices | awk 'NR>1 && $2=="device" {print $1}')" 82 NUM_CONNECTED="$(printf '%s\n' "$CONNECTED" | grep -c . || true)" 83 if [ "$NUM_CONNECTED" -eq 0 ]; then 84 echo "error: no devices connected. Plug in the phone and run 'adb devices'." >&2 85 exit 3 86 elif [ "$NUM_CONNECTED" -gt 1 ]; then 87 echo "error: multiple devices connected — pass --device <serial> to disambiguate." >&2 88 echo " connected:" >&2 89 printf ' %s\n' $CONNECTED >&2 90 exit 3 91 fi 92 DEVICE="$CONNECTED" 93 echo "==> auto-selected device: $DEVICE" 94fi 95if ! "$ADB" -s "$DEVICE" get-state >/dev/null 2>&1; then 96 echo "error: device $DEVICE is not connected." >&2 97 echo " adb devices output:" >&2 98 "$ADB" devices >&2 99 exit 3 100fi 101 102now_ms() { python3 -c 'import time; print(int(time.time()*1000))'; } 103 104confirm() { 105 if [ "$NO_CONFIRM" -eq 1 ]; then return 0; fi 106 printf '%s [y/N] ' "$1" 107 local response 108 read -r response 109 case "$response" in 110 [yY]|[yY][eE][sS]) return 0 ;; 111 *) return 1 ;; 112 esac 113} 114 115list_remote_logs() { 116 "$ADB" -s "$DEVICE" shell "ls -1 $REMOTE_LOGS_DIR 2>/dev/null" \ 117 | tr -d '\r' \ 118 | grep '\.json$' \ 119 || true 120} 121 122# 1. Snapshot existing logs so we can diff after the run. 123echo "==> Snapshotting existing logs on $DEVICE..." 124LOGS_BEFORE="$(list_remote_logs)" 125EXISTING_COUNT=$(printf '%s\n' "$LOGS_BEFORE" | grep -c '\.json$' || true) 126echo " ($EXISTING_COUNT existing log file(s))" 127 128# 2. Confirm the phone side is armed. 129if ! confirm "Phone ready? Model picked, Experiment Mode on, Start tapped?"; then 130 echo "Aborted by user." 131 exit 0 132fi 133 134# 3. Record t0 and play the video. 135T0_WALL_MS="$(now_ms)" 136echo "==> t0_wall_ms = $T0_WALL_MS" 137echo "==> Playing $VIDEO_ABS in QuickTime..." 138osascript \ 139 -e 'tell application "QuickTime Player" to activate' \ 140 -e "tell application \"QuickTime Player\" to open POSIX file \"$VIDEO_ABS\"" \ 141 -e 'tell application "QuickTime Player" to set current time of front document to 0' \ 142 -e 'tell application "QuickTime Player" to play front document' >/dev/null 143 144# 4. Wait the requested duration. 145echo "==> Sleeping ${DURATION}s..." 146sleep "$DURATION" 147 148# 5. Pause playback. 149echo "==> Pausing QuickTime..." 150osascript -e 'tell application "QuickTime Player" to pause front document' >/dev/null 151 152STOPPED_WALL_MS="$(now_ms)" 153 154# 6. Prompt the user to tap Stop on the phone. 155if [ "$NO_CONFIRM" -eq 0 ]; then 156 echo 157 echo "==> Tap 'Stop Experiment' on the phone now." 158 printf " Press Enter when done... " 159 read -r _ 160fi 161 162# 7. Diff the file list, pull anything new. 163LOGS_AFTER="$(list_remote_logs)" 164NEW_LOGS="$(comm -13 <(printf '%s\n' "$LOGS_BEFORE" | sort -u) <(printf '%s\n' "$LOGS_AFTER" | sort -u) | grep '\.json$' || true)" 165 166RUN_ID="${T0_WALL_MS}_${SAFE_TAG}" 167RUN_DIR="$EXPERIMENTS_DIR/$RUN_ID" 168mkdir -p "$RUN_DIR" 169 170if [ -z "$NEW_LOGS" ]; then 171 echo "warning: no new log files appeared on the phone. Was Experiment Mode" >&2 172 echo " actually started/stopped? Was a model selected? The manifest" >&2 173 echo " will still be written so you can debug, but the run is empty." >&2 174else 175 echo "==> Pulling new log(s) into $RUN_DIR/" 176 while IFS= read -r f; do 177 [ -z "$f" ] && continue 178 "$ADB" -s "$DEVICE" pull "$REMOTE_LOGS_DIR/$f" "$RUN_DIR/" >/dev/null 179 echo " pulled $f" 180 done <<< "$NEW_LOGS" 181fi 182 183# 8. Write the manifest. Use python for JSON to avoid quoting headaches. 184DEVICE_MANUFACTURER="$("$ADB" -s "$DEVICE" shell getprop ro.product.manufacturer 2>/dev/null | tr -d '\r' || true)" 185DEVICE_MODEL_NAME="$("$ADB" -s "$DEVICE" shell getprop ro.product.model 2>/dev/null | tr -d '\r' || true)" 186DEVICE_LABEL="$DEVICE_MANUFACTURER $DEVICE_MODEL_NAME" 187 188NEW_LOGS_JOINED="$(printf '%s\n' "$NEW_LOGS" | tr '\n' ',' | sed 's/,$//')" 189 190RUN_ID="$RUN_ID" \ 191MODEL_TAG="$MODEL_TAG" \ 192VIDEO_ABS="$VIDEO_ABS" \ 193DURATION="$DURATION" \ 194T0_WALL_MS="$T0_WALL_MS" \ 195STOPPED_WALL_MS="$STOPPED_WALL_MS" \ 196DEVICE="$DEVICE" \ 197DEVICE_LABEL="$DEVICE_LABEL" \ 198NEW_LOGS_JOINED="$NEW_LOGS_JOINED" \ 199python3 -c ' 200import json, os 201files = [f for f in os.environ["NEW_LOGS_JOINED"].split(",") if f] 202manifest = { 203 "run_id": os.environ["RUN_ID"], 204 "model_tag": os.environ["MODEL_TAG"], 205 "video_path": os.environ["VIDEO_ABS"], 206 "duration_seconds": float(os.environ["DURATION"]), 207 "t0_wall_ms": int(os.environ["T0_WALL_MS"]), 208 "stopped_wall_ms": int(os.environ["STOPPED_WALL_MS"]), 209 "device_serial": os.environ["DEVICE"], 210 "device_label": os.environ["DEVICE_LABEL"].strip(), 211 "log_files": files, 212} 213print(json.dumps(manifest, indent=2)) 214' > "$RUN_DIR/manifest.json" 215 216echo "==> Wrote $RUN_DIR/manifest.json" 217echo 218echo "Run dir: $RUN_DIR" 219echo "Next: tools/compare_logs.py experiments/ (after at least 2 runs against the same video)"