RFC-0021: Trace Processor report Subcommand
#5300
Replies: 1 comment
|
📝 RFC Document Updated View changes: Commit History |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
📄 RFC Doc: 0021-trace-processor-report-subcommand.md
Trace Processor
reportSubcommandAuthors: @lalitm
Status: Draft
Motivation
Perfetto traces are rich, multi-dimensional datasets. Today, extracting a
useful summary requires either:
TraceSummarySpectextprotos for thesummarizesubcommand.None of these serve the "I just collected a trace, what's in it?" use case
well. Users coming from
perf reportexpect to point a tool at a data fileand immediately see an opinionated, useful summary: no query authoring, no
spec files, no UI.
This gap is especially felt by:
performance.
summary as a build artifact, and to compare traces across builds.
Decision
Pending
Design
Relationship to
summarizeThe two subcommands split by who decides what is computed:
summarizeis for summaries the user asks for themselves: theyauthor
TraceSummarySpecprotos defining exactly what to compute.reportis opinionated summaries we give the user: built-in viewsover the common trace dimensions, with no authoring required.
Under the hood both are PerfettoSQL.
summarizeconverts query results toprotos as directed by the user's spec, with typed schemas and semantics
such as higher/lower-is-better;
reportis a presentation layer over thePerfettoSQL standard library, where each view is computed by curated
stdlib queries and rendered from a hand-written proto schema
(
report.proto, one message per view). Two things follow:summarizederives its outputschema from the user's spec because the computation is arbitrary;
report's views are a closed, compile-time set, so a hand-written protogives stable text/JSON output directly.
fixed in a module all SQL users benefit from, and the queries shown in
the SQL drill-down hints are the same ones the tool runs.
CLI surface
The first positional is always a noun (what data you are looking at); the
second is always a view (how to see it), from a closed per-noun set with a
default:
processestabletrackstableslicestable,histogram,timeline,inspectstack-samplesfunctions,top-down,bottom-upheap-profilefunctions,top-down,bottom-upheap-dumptypesschedulingsummary,timeline,inspectcounterslist,timeline,histogram,inspectWith no noun, the overview covers every noun that has data in the trace,
skipping the rest.
processes,tracks, andcounters listexist forstructural discovery: they enumerate the names that the scoping flags and
the other views take as input, so a user can orient in an unfamiliar trace
before drilling down. Output shape is statically known per (noun, view).
The nouns are deliberately generic trace primitives, applicable to any
trace regardless of origin. Domain-specific reporting (e.g. Android frame
timeline, ANRs, battery) is out of scope for now; it may be added in the
future.
Output format flags
text: human-readable tables, similar toperf report --stdio.json: one stable schema per (noun, view), generated fromreport.proto, with the scope context embedded and richer stats thantext (e.g. p50/p95/p99 where text shows min/avg/max). Text output is
explicitly not a stable interface; JSON is.
--show-sqlis what makes the SQL escape hatch concrete: the printedqueries are the ones the view ran, and a starting point for going beyond
what
reportoffers.Scoping flags
These filter the report to a subset of the trace data:
Scoping flags are translated into structured filters on the underlying
stdlib queries. Every invocation carries its full scope in flags; there is
no sticky state, so commands are reproducible, CI-safe, and safe for
concurrent clients of one warm session.
Filtering and aggregation control
Warm sessions
RFC 0031's
--remotesubcommand list growsreport. The interactivedrill-down loop (overview -> view -> inspect) is a rapid sequence of
invocations against one trace, the pattern warm sessions exist to serve.
Overview output
When invoked without a noun, the overview produces a one-line trace context
followed by per-noun highlights, ending with drill-down hints. The overview
accepts the scoping flags and
--top(applied per section);--nameand--sortare rejected, since the sections have disjoint name spaces andsort keys.
Example (
--format text):View semantics
Tree views
The tree views (
top-down,bottom-up) are never dumped in full. Nodesare included best-first under the
--max-linesbudget, scored by total%with a depth decay (internal, not user-configurable). Single-child chains
are collapsed to the same indent, and pruned subtrees are summarized:
functionsand the tree views show both self and total, with selfdisplayed more prominently.
timelineandhistogramtimelinebuckets the trace (or the--timerange) and renders one lineper bucket: an ASCII bar, the value, and the dominant entries in that
bucket.
scheduling timelineneeds no selection (CPU load per bucket,plus the threads that dominate each bucket);
slices timelineandcounters timelinetake a--nameand showcount and total duration, or average value, per bucket.
histogramrenders the distribution of a single series: durations of aslice name, or values of a counter. The output labels its scale (linear or
logarithmic) so bucket widths are not misread; JSON carries percentile
stats alongside the buckets.
inspectinspectdrills from a noun's aggregate into instances. The noun's normalfilters select the entity; scoping flags narrow which instances match. The
output shape is fixed per noun: aggregate stats over the matched instances
plus the instances themselves, rendered in full detail when exactly one
matches.
--namemust resolve to one distinct name (usually copy-pastedfrom report output); many instances of that name are not an error: the
output is a wider instance table plus a hint on how to narrow.
slices inspect --name <n>: instance count, duration percentiles, topinstances by duration (each carrying its ts/thread for narrowing). A
unique match shows dur, self dur, args, parent chain, and children.
counters inspect --name <n>: value at--ts, plus min/avg/max anddelta over the scoped range.
scheduling inspect --thread <t> --ts <ts>: state, CPU, end state,waker thread, and wakeup latency: "why was this thread not running at T".
Adding an inspect view to a noun must pass a two-part test: (1) instances
are addressable by name or coordinates, never tool-emitted ids; (2) it
answers an instance-level question the aggregate views do not.
Coverage gap:
stack-samples,heap-profile, andheap-dumphave noinspect view yet. A per-source function inspect (callers/callees of one
function) is tractable under this grammar, since the noun fixes the data
source, but is left as future work; heap-graph objects remain id-only.
Until then, the tree views plus
--nameand the SQL hints cover these.Diffing
Comparing two traces of the same workload (before/after a change, across
builds in CI) is an explicit goal. Any table view, and the overview,
accepts:
Diff is a presentation-layer join: the view's queries run independently on
each trace, and the two typed results are joined on the view's aggregation
key (slice name, function, thread, process, track, or counter name) in the
shell. Neither engine ever sees both traces; multi-trace queries are out
of scope, both because they are very hard to reason about and because
sessions are single-trace (RFC 0031). Because the two runs are
independent, target and baseline may each be a path or a warm-session
address, in any combination.
Semantics:
Default sort is the duration delta;
--sortselects others (e.g. countdelta). Rows present on only one side are marked added/removed and rank
by absolute delta.
a footnote warns when they differ materially;
reportdoes not attemptto normalize for workload size and makes no claim of statistical
significance.
values (tids, addresses) is an open question.
tp report --baseline base.pftrace target.pftracediffs the overview: aper-noun digest of the biggest movements, the intended CI build artifact.
Tree and single-series views do not accept
--baselineinitially;structural tree diffs need their own design (see open questions). A flag
is easier to miss than a subcommand, so
--baselineis included in thereporthelp text's example block (as above).Per-view column definitions
Slices
tableAggregation key: slice name.
The noun covers sync and async slice tracks; instants (zero duration)
contribute to Count only. Durations sum per instance without overlap
deduplication, so % of trace can exceed 100 on async-heavy traces.
stack-samples functionsheap-profile functionsheap-dump typesRetained size needs a dominator-tree computation and the Total%/Total
bytes columns need callstack ancestry walks; these are the most expensive
views to compute, and a further reason
reportbenefits from warmsessions.
scheduling summaryprocesses/tracks/counters listDiscovery tables: Process, PID, CPU time, % of trace, top threads; Track,
Type, Event count, Process/Thread; Counter name, Track/Process, Sample
count, Min, Avg, Max.
Output contract
Every view emits:
the invocation (see the overview example).
(including
--remoteand scope flags), includingtp querycommandsfor raw data. The intended progression is: overview -> aggregate view
-> inspect -> SQL.
TTY; piped or redirected output is untruncated.
required flag (e.g.
--tsforscheduling inspect), or a malformedvalue exits non-zero with a message listing the valid options; with
--format jsonthe error is a structured object.Testing
Text output is locked by trace processor diff tests: one golden per
(noun, view) over reference traces, so any output change is explicit in
review and documented behavior cannot drift from shipped behavior. JSON is
validated against
report.protoby construction.Alternatives considered
Build on the summarize machinery
Pro:
summarize.Con:
"pre-authored spec" is really a template rewritten per invocation.
Alternative grammars
Two other grammars were drafted: a
--viewflag on a noun positional, andview-first positionals with data-selection flags (
top-down --heap-profile). Both rejected: noun-then-view matches how users approacha trace (pick the data, then the presentation) and how comparable
heterogeneous profiling tools have converged, keeps each view a closed
per-noun set, and has in-repo precedent (
tp server http).Sticky server-side session state
Holding analysis state (a selected thread, zoom/filter stacks) in a
long-lived server makes interactive drill-down terse, but single
invocations become non-reproducible and concurrent clients unsafe. Warm
sessions (RFC 0031) already give the real benefit, parse-once performance,
so
reportkeeps all state in flags.Id-based inspect addressing
inspect slice:187432style handles: rejected. Ids are only knowable ifthe tool emitted them and are unstable across trace loads and versions;
names and coordinates (thread, ts) are legible from any output. Id-precision
lookups remain available via the SQL bridge.
A
--focus <function>stack filterA pprof-style focus transform (keep stacks containing X, re-root per view):
rejected as a second drill-down mechanism with subtle semantics (recursion
double-counting, per-view re-rooting).
bottom-up --namecovers thecallers workflow; re-rooting is left as an open question.
A separate
diffsubcommandtp report diff <base> <target>was considered. Rejected: it would need toreplicate every noun/view under itself, whereas
--baselinecomposes withthe existing views and the overview for free, and inherits scoping flags.
Open questions
similar have stdlib modules but are out of scope for now; they may be
added in the future.
(callers/callees) and heap-graph object drill-down (see coverage gap).
--baseline; therendering and matching rules need their own design.
--timeapplies to both traces;comparing different windows (e.g. startup vs startup at different
offsets) may need a
--baseline-time.addresses) break the exact-name join into spurious added/removed pairs.
separate real movement from run-to-run variance.
--root <function>on tree views: pure re-rooting for "what does Xcall", if hop-wise navigation proves insufficient.
nouns (the CLI analog of a vertical line in the UI).
(help section vs a dedicated subcommand).
💬 Discussion Guidelines:
All reactions