mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Feat] (tools): the cross-host acceptance driver and its report reducer, and a note that netbench's nc sink understates the link
This commit is contained in:
@@ -76,8 +76,19 @@ server hang at eglMakeCurrent. Exit 0 = end to end, 1 = middlebox,
|
||||
2 = filtered. Fix: `ip route replace <phone>/32 via <LAN gateway> dev eth0`
|
||||
as root in WSL (temporary; delete it afterwards).
|
||||
|
||||
## crosshost_accept.sh + crosshost_report.py — P12 exit gate (b)
|
||||
|
||||
A WSL client replays the openra and rd12 traces against the phone's render server over
|
||||
TCP + stream (ssim gate, then `PRESENT_CREDIT` 1/2/3 benchmarks). Adds a temporary /32 route
|
||||
around the host's TUN proxy, checks the path with `tcp_path_check.sh`, and removes the route and
|
||||
stops the server on exit. `crosshost_report.py` reduces the output to a table. Results and the
|
||||
P6.5 link numbers: `docs/Disaggregated/notes/p12/CROSSHOST-ACCEPTANCE.md`.
|
||||
|
||||
## netbench.sh — Wi-Fi TCP throughput baseline
|
||||
|
||||
**Understates the link**: the `toybox nc` sink capped at 18-22 MiB/s while the render server
|
||||
read 52 MB/s on the same Wi-Fi. Use the server's `P65ServerFrame` read rate as the throughput number.
|
||||
|
||||
WSL -> phone bulk transfer over `toybox nc` sink, 3 reps; refuses to run
|
||||
unless `tcp_path_check.sh` passes. The `nc` listener must keep stdin open or it
|
||||
exits on EOF and RSTs the connection, and `pkill` must be anchored
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
# P12 exit gate (b): a client on ANOTHER machine (WSL on the Windows host) replays the in-world
|
||||
# Minecraft trace against the phone's render server over TCP + stream data plane, and the P6.5
|
||||
# link numbers are recorded. Run from Git Bash. Results: $PERF_WORK/crosshost/<run>/.
|
||||
#
|
||||
# bash crosshost_accept.sh # ssim gate for both traces, then credit 1/2/3 benchmarks
|
||||
# RUNS="ssim:openra bench:rd12:1" bash crosshost_accept.sh
|
||||
#
|
||||
# The WSL default route may be a TUN proxy (see tcp_path_check.sh). This script adds a temporary
|
||||
# /32 route around it for the phone, and removes it on exit.
|
||||
set -u
|
||||
export MSYS_NO_PATHCONV=1
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO="$(cd "$HERE/../../.." && pwd)"; REPO_WIN="$(cygpath -m "$REPO")"
|
||||
SER="${SER:-2f7cbe2e}"
|
||||
PKG="${PKG:-top.mobilegl.plugin.trace}"
|
||||
PHONE="${PHONE:-192.168.21.181}"
|
||||
GATEWAY="${GATEWAY:-192.168.31.1}"
|
||||
TOKEN="${TOKEN:-crosshost-token-2026-09}"
|
||||
WSL="${WSL_DISTRO:-Ubuntu}"
|
||||
PERF_WORK="${PERF_WORK:-$REPO/.trace-work/perf-compare}"
|
||||
RUNS="${RUNS:-ssim:openra ssim:rd12 bench:openra:1 bench:openra:2 bench:openra:3 bench:rd12:1 bench:rd12:2 bench:rd12:3}"
|
||||
TRACES='$HOME/wifi-perf/traces'
|
||||
WSL_OUT='$HOME/wifi-perf/out/crosshost'
|
||||
LOCAL_OUT="$PERF_WORK/crosshost"
|
||||
log() { echo "[$(date +%H:%M:%S)] $*"; }
|
||||
|
||||
cleanup() {
|
||||
wsl.exe -d "$WSL" -u root -- ip route del "$PHONE/32" via "$GATEWAY" dev eth0 2>/dev/null
|
||||
python "$REPO_WIN/tools/trace_replay/tcp_device_server.py" stop --serial "$SER" --package "$PKG" >/dev/null 2>&1
|
||||
log "cleanup: temporary route removed, server stopped"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wsl.exe -d "$WSL" -u root -- ip route replace "$PHONE/32" via "$GATEWAY" dev eth0 || exit 1
|
||||
bash "$HERE/tcp_path_check.sh" || { log "FATAL: path is not end to end"; exit 1; }
|
||||
|
||||
adb -s "$SER" logcat -c
|
||||
python "$REPO_WIN/tools/trace_replay/tcp_device_server.py" start --serial "$SER" --package "$PKG" \
|
||||
--backend DirectGLES --listen tcp://0.0.0.0:40613 --token "$TOKEN" >/dev/null 2>&1 || { log "FATAL: server start"; exit 1; }
|
||||
for i in $(seq 1 30); do
|
||||
adb -s "$SER" logcat -d -s MobileGL:* | tr -d '\r' | grep -q 'listening on tcp://0.0.0.0:40613' && break; sleep 1
|
||||
done
|
||||
adb -s "$SER" logcat -d -s MobileGL:* | tr -d '\r' | grep -q 'listening on tcp://0.0.0.0:40613' || { log "FATAL: server not listening"; exit 1; }
|
||||
log "server listening on $PHONE:40613 (phone $(adb -s "$SER" shell dumpsys battery | tr -d '\r' | sed -n 's/.*temperature: \([0-9]*\).*/\1/p' | head -1) x0.1C)"
|
||||
|
||||
mkdir -p "$LOCAL_OUT"
|
||||
for run in $RUNS; do
|
||||
IFS=: read -r mode wl credit <<<"$run"
|
||||
[ "$mode" = ssim ] && credit=1
|
||||
name="$mode-$wl${credit:+-c$credit}"; [ "$mode" = ssim ] && name="ssim-$wl"
|
||||
case "$wl" in
|
||||
openra) trace=openra; golden=openra.0000031249.png; target=31249; geom="--width 640 --height 480 --crop-x 1 --crop-y 1 --crop-width 638 --crop-height 478"; tmo=600 ;;
|
||||
rd12) trace=minecraft-1.21.4-rd12-odinlite-in-world; golden=minecraft-1.21.4-rd12-odinlite-in-world.0004660351.png; target=4660351; geom="--width 854 --height 480"; tmo=1500 ;;
|
||||
*) log "unknown workload $wl"; continue ;;
|
||||
esac
|
||||
if [ "$mode" = ssim ]; then
|
||||
mode_args="--target-call $target --golden $TRACES/$golden --ssim-threshold 0.99 $geom"
|
||||
else
|
||||
mode_args="--benchmark --benchmark-result=$WSL_OUT/$name/benchmark.json"
|
||||
fi
|
||||
# One session at a time: no stray client of ours, and the previous session child reaped, or the
|
||||
# supervisor answers Refuse{Busy} and the run measures nothing.
|
||||
wsl.exe -d "$WSL" -- pkill -f mobilegl_trace_replay 2>/dev/null
|
||||
for i in $(seq 1 60); do
|
||||
n=$(adb -s "$SER" shell 'ps -A -o NAME | grep -c "^libMobileGLServer.so"' | tr -d '␍')
|
||||
[ "${n:-0}" -le 1 ] && break; sleep 1
|
||||
done
|
||||
[ "${n:-0}" -le 1 ] || { log "FATAL: a session child is still alive after 60 s"; exit 1; }
|
||||
log "RUN $name"
|
||||
adb -s "$SER" logcat -c
|
||||
wsl.exe -d "$WSL" -- bash -c "
|
||||
set -u; cd ~/MobileGL; rm -rf $WSL_OUT/$name; mkdir -p $WSL_OUT/$name
|
||||
export MOBILEGL_TRANSPORT=spawn MOBILEGL_IPC_CONTROL=tcp://$PHONE:40613 MOBILEGL_IPC_DATA=stream
|
||||
export MOBILEGL_IPC_TOKEN=$TOKEN MOBILEGL_IPC_RUN_AHEAD=1 MOBILEGL_IPC_COLD_START_MS=120000
|
||||
export MOBILEGL_IPC_PRESENT_CREDIT=$credit MOBILEGL_PIPE_STATS=1
|
||||
SECONDS=0
|
||||
timeout $tmo ./build-split/tools/trace_replay/mobilegl_trace_replay --trace $TRACES/$trace.trace \
|
||||
--backend DirectGLES --mobilegl-library ./build-split/libMobileGL.so --pbuffer-surface \
|
||||
--output $WSL_OUT/$name $mode_args > $WSL_OUT/$name/mobilegl.log 2>&1
|
||||
echo rc=\$? secs=\$SECONDS > $WSL_OUT/$name/rc.txt"
|
||||
mkdir -p "$LOCAL_OUT/$name"
|
||||
cp -r "//wsl.localhost/$WSL/home/swung/wifi-perf/out/crosshost/$name/." "$LOCAL_OUT/$name/" 2>/dev/null
|
||||
adb -s "$SER" logcat -d > "$LOCAL_OUT/$name/phone-logcat.txt" 2>/dev/null
|
||||
log " $(cat "$LOCAL_OUT/$name/rc.txt" 2>/dev/null) $(grep -o '"ssim": [-0-9.]*' "$LOCAL_OUT/$name/result.json" 2>/dev/null | head -1) $(grep -o '"fps": [0-9.]*' "$LOCAL_OUT/$name/benchmark.json" 2>/dev/null)"
|
||||
sleep 3
|
||||
done
|
||||
log "ALL DONE"
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Reduce crosshost_accept.sh output (.trace-work/perf-compare/crosshost/<run>/) to a table."""
|
||||
import json, os, re, statistics, sys
|
||||
|
||||
root = sys.argv[1] if len(sys.argv) > 1 else os.path.join(
|
||||
os.path.dirname(__file__), "..", "..", "..", ".trace-work", "perf-compare", "crosshost")
|
||||
|
||||
def load(path):
|
||||
try:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def kv(line):
|
||||
return dict(re.findall(r"(\w+)=([^\s]+)", line))
|
||||
|
||||
rows = []
|
||||
for name in sorted(os.listdir(root)):
|
||||
d = os.path.join(root, name)
|
||||
if not os.path.isdir(d):
|
||||
continue
|
||||
rc = open(os.path.join(d, "rc.txt")).read().strip() if os.path.exists(os.path.join(d, "rc.txt")) else "?"
|
||||
res = load(os.path.join(d, "result.json")) or {}
|
||||
bench = load(os.path.join(d, "benchmark.json")) or {}
|
||||
summary = {}
|
||||
frame_bytes = {}
|
||||
client = os.path.join(d, "mobilegl.client.log")
|
||||
if os.path.exists(client):
|
||||
for line in open(client, encoding="utf-8", errors="replace"):
|
||||
if "P65LinkMetrics kind=summary" in line:
|
||||
summary = kv(line)
|
||||
elif "P65LinkMetrics kind=frame " in line:
|
||||
f = kv(line)
|
||||
frame_bytes[int(f["frame"])] = int(f["stage_bytes"])
|
||||
ft = bench.get("frameTimesMs") or []
|
||||
# Steady state = every frame after the first (the load frame carries the whole texture upload).
|
||||
steady = [k for k in sorted(frame_bytes) if 2 <= k <= len(ft)]
|
||||
steady_s = sum(ft[k - 1] for k in steady) / 1000 if steady else 0
|
||||
steady_mb = sum(frame_bytes[k] for k in steady) / 1e6 if steady else 0
|
||||
rows.append({
|
||||
"run": name, "rc": rc,
|
||||
"ssim": res.get("ssim") if "ssim" in name else None,
|
||||
"frames": bench.get("totalFrames"),
|
||||
"fps": bench.get("fps"), "mean_ms": bench.get("meanFrameMs"),
|
||||
"median_ms": bench.get("medianFrameMs"), "p95_ms": bench.get("p95FrameMs"),
|
||||
"first_frame_s": round(ft[0] / 1000, 1) if ft else None,
|
||||
"steady_fps": round(1000 / statistics.median(ft[1:]), 1) if len(ft) > 2 else None,
|
||||
"steady_MB_per_frame": round(steady_mb / len(steady), 2) if steady else None,
|
||||
"steady_MBps": round(steady_mb / steady_s, 1) if steady_s else None,
|
||||
"wait_replies": summary.get("wait_replies"),
|
||||
"rtt_mean_ms": round(float(summary["rtt_mean_us"]) / 1000, 1) if "rtt_mean_us" in summary else None,
|
||||
"rtt_p50_ub_ms": round(int(summary["rtt_p50_upper_us"]) / 1000, 1) if "rtt_p50_upper_us" in summary else None,
|
||||
"rtt_p99_ub_ms": round(int(summary["rtt_p99_upper_us"]) / 1000, 1) if "rtt_p99_upper_us" in summary else None,
|
||||
"stage_MB": round(int(summary["stage_bytes"]) / 1e6) if "stage_bytes" in summary else None,
|
||||
"client_cpu_s": round(int(summary["client_thread_cpu_ns"]) / 1e9, 1) if "client_thread_cpu_ns" in summary else None,
|
||||
"wall_s": round(int(summary["wall_ns"]) / 1e9, 1) if "wall_ns" in summary else None,
|
||||
})
|
||||
|
||||
cols = ["run", "rc", "ssim", "frames", "fps", "steady_fps", "median_ms", "p95_ms", "first_frame_s",
|
||||
"steady_MB_per_frame", "steady_MBps", "wait_replies", "rtt_mean_ms", "rtt_p50_ub_ms", "rtt_p99_ub_ms", "stage_MB", "client_cpu_s", "wall_s"]
|
||||
print("| " + " | ".join(cols) + " |")
|
||||
print("|" + "---|" * len(cols))
|
||||
for r in rows:
|
||||
print("| " + " | ".join("" if r[c] is None else str(r[c]) for c in cols) + " |")
|
||||
Reference in New Issue
Block a user