[Tools] (P14): the sampler and profiler find spawn and tcp server processes by their install path, plus a per-component profile split.

This commit is contained in:
2026-10-07 10:27:01 -04:00
parent 8346d80999
commit 0b0089e599
3 changed files with 69 additions and 3 deletions
+66
View File
@@ -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 <perf.data> <binary_cache> <thread comm> [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()
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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