mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Tools] (P14): benchmark runs default to no per-frame glFinish, plus FCL and layer-split helpers.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# FCL Minecraft in-world fps for P14: swaps FCL's built-in libMobileGL.so (rooted device), picks
|
||||
# the backend through FCL's own renderer id and the transport through debug.mobilegl.transport,
|
||||
# launches FCL (it auto-enters the last world), and reads MobileGL's opt-in fps log
|
||||
# (debug.mobilegl.fps_log=1, one line about every 2 s) over a steady window.
|
||||
#
|
||||
# SER=HA27Q3LQ LIBS="dev=<path> feat=<path>" CONFIGS="dev:DirectGLES feat:DirectGLES:inproc ..." \
|
||||
# REPS=2 WARMUP=45 WINDOW=30 bash fcl_p14.sh run|restore
|
||||
#
|
||||
# The original library is saved once to /data/local/tmp/p14-fcl-orig.so and put back by
|
||||
# `restore` (md5-checked), along with config.json and the two properties. Clocks are the
|
||||
# caller's (pin_clocks.sh). FCL can die by itself at start-up (DEBTS.md, SIGRTMIN+2): a run with
|
||||
# no fps lines is retried once.
|
||||
set -u
|
||||
export MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*'
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
SER="${SER:-HA27Q3LQ}"
|
||||
FCL="${FCL:-com.tungsten.fcl.mgdebug.debug}"
|
||||
REPS="${REPS:-2}" WARMUP="${WARMUP:-45}" WINDOW="${WINDOW:-30}"
|
||||
OUT="${PERF_WORK:-$REPO_ROOT/.trace-work/perf-p14}/${TAG:-fcl}"
|
||||
ESPRYT_ID=5e273ee2-baca-4c81-8e48-b63feefb9ba8
|
||||
MAGMA_ID=2be0dc10-1eef-4ce2-b512-b266dd33fd9e
|
||||
mkdir -p "$OUT"
|
||||
su_sh() { adb -s "$SER" shell "su -c '$1'"; }
|
||||
libdir() { su_sh "dirname /data/app/*/$FCL-*/lib/arm64/libMobileGL.so" | tr -d '\r' | head -1; }
|
||||
CFG=/data/data/$FCL/files/config.json
|
||||
|
||||
save_original() {
|
||||
local dir; dir=$(libdir)
|
||||
# The renderer switch, as a device-side script: sed's own quotes cannot survive two shells.
|
||||
printf '%s\n' 'sed -i "s/\"renderer\": \"[^\"]*\"/\"renderer\": \"$1\"/" "$2"' >"$OUT/p14-fcl-set.sh"
|
||||
adb -s "$SER" push "$(cygpath -w "$OUT/p14-fcl-set.sh")" /data/local/tmp/p14-fcl-set.sh >/dev/null
|
||||
su_sh "test -f /data/local/tmp/p14-fcl-orig.so || cp $dir/libMobileGL.so /data/local/tmp/p14-fcl-orig.so; test -f /data/local/tmp/p14-fcl-config.json || cp $CFG /data/local/tmp/p14-fcl-config.json"
|
||||
}
|
||||
|
||||
install_lib() { # $1 host path
|
||||
local dir; dir=$(libdir)
|
||||
adb -s "$SER" push "$(cygpath -w "$1")" /data/local/tmp/p14-fcl-lib.so >/dev/null
|
||||
# cat into the existing file keeps its owner, mode and SELinux label.
|
||||
su_sh "cat /data/local/tmp/p14-fcl-lib.so > $dir/libMobileGL.so; rm -f /data/local/tmp/p14-fcl-lib.so"
|
||||
}
|
||||
|
||||
run_one() { # name backend transport rep
|
||||
local name="$1" backend="$2" transport="$3" rep="$4" dir="$OUT/$1-$2-$3-r$4"
|
||||
mkdir -p "$dir"
|
||||
local id=$ESPRYT_ID; [ "$backend" = DirectVulkan ] && id=$MAGMA_ID
|
||||
su_sh "am force-stop $FCL; sh /data/local/tmp/p14-fcl-set.sh $id $CFG; setprop debug.mobilegl.fps_log 1; setprop debug.mobilegl.transport $transport"
|
||||
adb -s "$SER" logcat -c
|
||||
local t0; t0=$(adb -s "$SER" shell dumpsys battery | tr -d '\r' | sed -n 's/.*temperature: \([0-9]*\).*/\1/p')
|
||||
su_sh "input keyevent KEYCODE_WAKEUP; monkey -p $FCL -c android.intent.category.LAUNCHER 1" >/dev/null 2>&1
|
||||
sleep "$WARMUP"
|
||||
local pid; pid=$(adb -s "$SER" shell pidof $FCL | tr -d '\r' | awk '{print $NF}')
|
||||
adb -s "$SER" shell "su -c 'for t in /proc/$pid/task/*; do echo \$(cat \$t/comm) \$(cut -d\" \" -f1 \$t/schedstat); done'" >"$dir/cpu0.txt" 2>/dev/null
|
||||
sleep "$WINDOW"
|
||||
adb -s "$SER" shell "su -c 'for t in /proc/$pid/task/*; do echo \$(cat \$t/comm) \$(cut -d\" \" -f1 \$t/schedstat); done'" >"$dir/cpu1.txt" 2>/dev/null
|
||||
adb -s "$SER" logcat -d >"$dir/logcat.txt"
|
||||
su_sh "am force-stop $FCL"
|
||||
local t1; t1=$(adb -s "$SER" shell dumpsys battery | tr -d '\r' | sed -n 's/.*temperature: \([0-9]*\).*/\1/p')
|
||||
local lines; lines=$(grep -a "MobileGL fps:" "$dir/logcat.txt" | wc -l)
|
||||
echo "name=$name backend=$backend transport=$transport rep=$rep pid=$pid temp0=$t0 temp1=$t1 fpslines=$lines" >"$dir/meta.txt"
|
||||
grep -aE "Active backend type|debug.mobilegl.transport|MOBILEGL_TRANSPORT=inproc|run-ahead ARMED" "$dir/logcat.txt" | head -5 >"$dir/markers.txt"
|
||||
echo "$(cat "$dir/meta.txt") :: $(grep -a 'MobileGL fps:' "$dir/logcat.txt" | tail -3 | sed 's/.*MobileGL fps: //' | tr '\n' '|')"
|
||||
[ "$lines" -gt 0 ]
|
||||
}
|
||||
|
||||
case "${1:-run}" in
|
||||
run)
|
||||
save_original
|
||||
for ((r = 1; r <= REPS; r++)); do
|
||||
for cfg in $CONFIGS; do
|
||||
IFS=: read -r name backend transport <<<"$cfg"
|
||||
transport="${transport:-monolith}"
|
||||
lib=$(echo " $LIBS " | sed -n "s/.* $name=\([^ ]*\) .*/\1/p")
|
||||
install_lib "$lib"
|
||||
run_one "$name" "$backend" "$transport" "$r" || { sleep 10; run_one "$name" "$backend" "$transport" "$r" || true; }
|
||||
sleep "${COOL:-20}"
|
||||
done
|
||||
done ;;
|
||||
restore)
|
||||
dir=$(libdir)
|
||||
su_sh "am force-stop $FCL; cat /data/local/tmp/p14-fcl-orig.so > $dir/libMobileGL.so && md5sum $dir/libMobileGL.so; cat /data/local/tmp/p14-fcl-config.json > $CFG; setprop debug.mobilegl.fps_log ''; setprop debug.mobilegl.transport ''" ;;
|
||||
esac
|
||||
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Split one thread of a simpleperf profile by LAYER, in ms per frame.
|
||||
|
||||
python layers.py <perf.data> <binary_cache> <thread comm> <cpu_ms_per_frame> [--tail-ms=N]
|
||||
|
||||
Each sample goes to the layer of the first frame, walking from the leaf toward the root, that
|
||||
belongs to one: the GPU driver (vendor GLES/Vulkan libraries, kgsl), the backend (MG_Backend),
|
||||
the applier (MGPipeApply*, the record sink, the wire decoder), the client half (the frontend,
|
||||
the validate point and its emitters, the verb port, the wire encoder), or the replay harness
|
||||
(apitrace parsing and dispatch). Library code with no layer of its own (malloc, memcpy, atomics)
|
||||
lands in the layer that called it. Kernel frames count as the driver only below a driver frame.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from collections import Counter
|
||||
|
||||
sys.path.insert(0, os.environ.get("SIMPLEPERF_DIR", ""))
|
||||
from simpleperf_report_lib import ReportLib # noqa: E402
|
||||
|
||||
LAYERS = ["driver", "backend", "applier", "client half", "harness", "other"]
|
||||
|
||||
|
||||
def layer_of(symbol, dso):
|
||||
if any(k in dso for k in ("adreno", "libGLESv2", "libEGL_", "vulkan.", "libgsl", "libllvm-glnext", "msm_kgsl")):
|
||||
return "driver"
|
||||
if "MG_Backend::" in symbol:
|
||||
return "backend"
|
||||
if ("MGPipeApply" in symbol or "RecordVerbSink" in symbol or "PipeWireDecoder" in symbol
|
||||
or "PipeApplier::" in symbol or "ServerLoop::" in symbol):
|
||||
return "applier"
|
||||
if any(k in symbol for k in ("MG_Pipe::", "MG_Impl::", "MG_Record::", "MG_State::", "MG_Remote::Client",
|
||||
"PipeWireEncoder", "MG_Util::")) or "libMobileGL" in dso and symbol.startswith("gl"):
|
||||
return "client half"
|
||||
if any(k in symbol for k in ("trace::", "retrace", "Brotli", "mobilegl_apitrace", "mobilegl_trace")):
|
||||
return "harness"
|
||||
return None
|
||||
|
||||
|
||||
def tail_start(data, symfs, tail_ms):
|
||||
if not tail_ms:
|
||||
return 0
|
||||
lib = ReportLib()
|
||||
lib.SetRecordFile(data)
|
||||
lib.SetSymfs(symfs)
|
||||
last = 0
|
||||
while True:
|
||||
sample = lib.GetNextSample()
|
||||
if sample is None:
|
||||
break
|
||||
chain = lib.GetCallChainOfCurrentSample()
|
||||
if any("retrace::retraceCall" in chain.entries[i].symbol.symbol_name for i in range(chain.nr)):
|
||||
last = max(last, sample.time)
|
||||
return last - int(tail_ms * 1e6)
|
||||
|
||||
|
||||
def main():
|
||||
args = [a for a in sys.argv[1:] if not a.startswith("--tail-ms=")]
|
||||
tail = next((float(a.split("=", 1)[1]) for a in sys.argv[1:] if a.startswith("--tail-ms=")), 0.0)
|
||||
data, symfs, comm, cpu = args[0], args[1], args[2], float(args[3])
|
||||
start = tail_start(data, symfs, tail)
|
||||
lib = ReportLib()
|
||||
lib.SetRecordFile(data)
|
||||
lib.SetSymfs(symfs)
|
||||
counts = Counter()
|
||||
total = 0
|
||||
while True:
|
||||
sample = lib.GetNextSample()
|
||||
if sample is None:
|
||||
break
|
||||
if comm not in sample.thread_comm or sample.time < start:
|
||||
continue
|
||||
total += 1
|
||||
leaf = lib.GetSymbolOfCurrentSample()
|
||||
frames = [(leaf.symbol_name, leaf.dso_name)]
|
||||
chain = lib.GetCallChainOfCurrentSample()
|
||||
frames += [(chain.entries[i].symbol.symbol_name, chain.entries[i].symbol.dso_name) for i in range(chain.nr)]
|
||||
found = None
|
||||
for symbol, dso in frames:
|
||||
if "kallsyms" in dso:
|
||||
continue
|
||||
found = layer_of(symbol, dso)
|
||||
if found:
|
||||
break
|
||||
counts[found or "other"] += 1
|
||||
print(f"{comm}: {total} samples, {cpu:.2f} ms/frame")
|
||||
for name in LAYERS:
|
||||
share = counts[name] / max(1, total)
|
||||
print(f" {name:12} {100 * share:5.1f}% {cpu * share:6.2f} ms/frame")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -136,7 +136,7 @@ run_one() {
|
||||
done
|
||||
fi
|
||||
local passflag=""
|
||||
[ "$mode" = benchmark ] && passflag="--ez benchmark true --es benchmark_result_path $app/output/benchmark.json"
|
||||
[ "$mode" = benchmark ] && passflag="--ez benchmark true --ez benchmark_finish ${FINISH:-false} --es benchmark_result_path $app/output/benchmark.json"
|
||||
local env; env="$(arm_env "$arm")"; [ -n "$EXTRA_ENV" ] && env="${env:+$env;}$EXTRA_ENV"
|
||||
if [ "$mode" = benchmark ]; then
|
||||
shq "su -c 'nohup taskset 01 $SAMPLER $pkg 10 $app/output/benchmark.json /data/local/tmp/p14cpu.csv $TIMEOUT >/dev/null 2>&1 &'" >/dev/null 2>&1
|
||||
|
||||
@@ -37,7 +37,7 @@ adb -s "$SER" shell "su -c 'pkill -INT simpleperf; rm -f /data/local/tmp/p14perf
|
||||
adb -s "$SER" shell "su -c 'simpleperf record --app $pkg -e cpu-clock --call-graph fp -f $FREQ -o /data/local/tmp/p14perf.data'" >"$OUT/record.log" 2>&1 &
|
||||
sp_pid=$!
|
||||
sleep 2
|
||||
adb -s "$SER" shell "am start -a top.mobilegl.plugin.TRACE_REPLAY -n $pkg/top.mobilegl.plugin.trace.TraceReplayActivity --es trace_path $app/input-$WL/trace.trace --es golden_path $app/input-$WL/golden.png --es output_dir $app/output --es backend $BACKEND $args --ez use_pbuffer true --ez benchmark true --es benchmark_result_path $app/output/benchmark.json --es mobilegl_env '$env'" >/dev/null
|
||||
adb -s "$SER" shell "am start -a top.mobilegl.plugin.TRACE_REPLAY -n $pkg/top.mobilegl.plugin.trace.TraceReplayActivity --es trace_path $app/input-$WL/trace.trace --es golden_path $app/input-$WL/golden.png --es output_dir $app/output --es backend $BACKEND $args --ez use_pbuffer true --ez benchmark true --ez benchmark_finish ${FINISH:-false} --es benchmark_result_path $app/output/benchmark.json --es mobilegl_env '$env'" >/dev/null
|
||||
waited=0
|
||||
until adb -s "$SER" exec-out "run-as $pkg cat $app/output/benchmark.json" 2>/dev/null | grep -q '"fps"'; do
|
||||
sleep 1; waited=$((waited + 1)); [ "$waited" -ge 600 ] && break
|
||||
|
||||
Reference in New Issue
Block a user