From 0b0089e59925fcec709fd7b6cdba1c7ea8e0dcad Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Wed, 7 Oct 2026 10:27:01 -0400 Subject: [PATCH] [Tools] (P14): the sampler and profiler find spawn and tcp server processes by their install path, plus a per-component profile split. --- tools/device_bench/disagg/components.py | 66 ++++++++++++++++++++++++ tools/device_bench/disagg/cpusampler.c | 4 +- tools/device_bench/disagg/profile_p14.sh | 2 +- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 tools/device_bench/disagg/components.py diff --git a/tools/device_bench/disagg/components.py b/tools/device_bench/disagg/components.py new file mode 100644 index 00000000..c960e3ce --- /dev/null +++ b/tools/device_bench/disagg/components.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Inclusive share of fixed components on one thread of a simpleperf profile, converted to +milliseconds per frame with the thread's measured CPU ms/frame. + + python components.py [cpu_ms_per_frame] + +A sample counts toward a component when any frame of its call chain matches the component's +pattern (first match in COMPONENTS order wins for the 'exclusive' column, so the rows of that +column add up to 100%). +""" +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 + +COMPONENTS = [ + ("trace parse (harness)", ("trace::Parser::", "BrotliFile", "trace::Call::~Call", "trace::File::")), + ("validate point", ("MGPipeValidateForVerb",)), + ("backend draw setup", ("SetupWireDraw", "VulkanRenderer::SetupDraw", "DirectGLES::PrepareForDraw")), + ("backend draw other", ("DirectVulkan::DrawElements", "DirectGLES::DrawElements", "VulkanRenderer::DrawElements")), + ("verb port / record sink", ("EmitDrawRecord", "VerbChannel::Port", "RecordVerbSink::")), + ("wire encode (client)", ("ClientSession::Emit", "PipeWireEncoder::")), + ("apply decode", ("PipeWireDecoder::", "PipeApplier::ApplyOne")), + ("apply loop idle/poll", ("ServerLoop::ApplyThreadMain", "ServerLoop::DrainRing")), + ("other GL entry points", ("retrace::retraceCall",)), +] + + +def main(): + data, symfs, comm = sys.argv[1], sys.argv[2], sys.argv[3] + cpu = float(sys.argv[4]) if len(sys.argv) > 4 else None + lib = ReportLib() + lib.SetRecordFile(data) + lib.SetSymfs(symfs) + total = 0 + inclusive = Counter() + exclusive = Counter() + while True: + sample = lib.GetNextSample() + if sample is None: + break + if comm not in sample.thread_comm: + continue + total += 1 + frames = [lib.GetSymbolOfCurrentSample().symbol_name] + chain = lib.GetCallChainOfCurrentSample() + frames += [chain.entries[i].symbol.symbol_name for i in range(chain.nr)] + first = None + for name, patterns in COMPONENTS: + if any(p in f for f in frames for p in patterns): + inclusive[name] += 1 + if first is None: + first = name + exclusive[first or "rest"] += 1 + print(f"{comm}: {total} samples" + (f", {cpu:.2f} ms/frame" if cpu else "")) + for name, _ in COMPONENTS + [("rest", ())]: + inc = 100.0 * inclusive[name] / max(1, total) + exc = 100.0 * exclusive[name] / max(1, total) + ms = f" {cpu * exc / 100.0:6.2f} ms" if cpu else "" + print(f" {name:28} incl {inc:5.1f}% excl {exc:5.1f}%{ms}") + + +if __name__ == "__main__": + main() diff --git a/tools/device_bench/disagg/cpusampler.c b/tools/device_bench/disagg/cpusampler.c index cfadd460..445e52c8 100644 --- a/tools/device_bench/disagg/cpusampler.c +++ b/tools/device_bench/disagg/cpusampler.c @@ -95,9 +95,9 @@ static int ScanPids(const char* pkg, int* pids) { snprintf(path, sizeof path, "/proc/%s/cmdline", e->d_name); if (ReadSmall(path, buf, sizeof buf) <= 0) continue; // The replay process (and its :services), plus the render-server processes the spawn and - // tcp arms exec (their cmdline is the server library's name, not the package's). + // tcp arms exec (their cmdline is the server library's path in the package's install dir). if ((strncmp(buf, pkg, len) == 0 && (buf[len] == 0 || buf[len] == ':')) || - strncmp(buf, "libMobileGLServer.so", 20) == 0) + (strstr(buf, "libMobileGLServer.so") != NULL && strstr(buf, pkg) != NULL)) pids[n++] = atoi(e->d_name); } closedir(d); diff --git a/tools/device_bench/disagg/profile_p14.sh b/tools/device_bench/disagg/profile_p14.sh index 0dee13e4..d08bba9d 100644 --- a/tools/device_bench/disagg/profile_p14.sh +++ b/tools/device_bench/disagg/profile_p14.sh @@ -33,7 +33,7 @@ esac adb -s "$SER" shell "am force-stop $PKG_FEAT; am force-stop $PKG_DEV; run-as $pkg sh -c 'rm -f $app/output/*.json'" >/dev/null 2>&1 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 sleep "$DELAY" -pids=$(adb -s "$SER" shell "su -c 'echo \$(pidof $pkg) \$(pgrep -f ^libMobileGLServer.so)'" | tr -d '\r' | tr -s ' ' ',' | sed 's/^,//; s/,$//') +pids=$(adb -s "$SER" shell "su -c 'echo \$(pidof $pkg) \$(pgrep -f $pkg.*libMobileGLServer.so)'" | tr -d '\r' | tr -s ' ' ',' | sed 's/^,//; s/,$//') echo "pids=$pids" | tee "$OUT/pids.txt" adb -s "$SER" shell "su -c 'simpleperf record -e cpu-clock -p $pids --call-graph fp -f 4000 --duration $DUR -o /data/local/tmp/p14perf.data'" >"$OUT/record.log" 2>&1 adb -s "$SER" exec-out "run-as $pkg cat $app/output/benchmark.json" >"$OUT/benchmark.json" 2>/dev/null