RFC-0019: Trace Processor Parse Cache #4960
Replies: 2 comments
|
This doc was subsequently replaced by #6234 for fast querying of traces across multiple trace-procesor versions. Then for disk based exporting, it was replaced by #6839 where we now have an opaque (in practice, Apache Arrow) format for exporting data from trace processor and then reimporting it back. |
0 replies
|
📝 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: 0019-trace-processor-parse-cache.md
Trace Processor Parse Cache
Authors: @lalitm
Status: Superseded
For fast repeated queries, this proposal was replaced by
RFC-0031, which keeps a parsed trace
warm for repeated queries, including workflows using multiple Trace Processor
versions. For disk-based export and
reimport, it was replaced by the opaque streaming table export format in
#6839.
Problem
Loading large traces (multi-GB) into Trace Processor is slow. Parsing
protobuf trace data, sorting events, and populating tables can take minutes
for large traces. This cost is paid on every load, even when the trace
hasn't changed.
This is painful in several workflows:
refresh or browser restart.
each cycle re-parses from scratch.
TraceProcessorinstance on the same trace during development.The parsed table representation is deterministic for a given trace + TP
version + flags. Re-parsing is pure waste when the inputs haven't changed.
Decision
Add a parse cache that serializes parsed tables into an opaque binary
format and transparently loads from cache on subsequent opens. The caching
logic lives entirely in the shell layer — the TP core remains IO-free.
Design
Cache format
The parse cache format is an internal implementation detail of Trace
Processor. It is not stable, not versioned for external consumers, and
carries no forwards or backwards compatibility guarantees. The format
may change between any two TP releases without notice.
Currently, the cache is a TAR archive of Arrow IPC files (one per intrinsic
table), reusing the existing
ExportToArrow()/ Arrow TAR importinfrastructure. This is a convenient implementation choice, not a public
contract.
A separate, stable Arrow export feature (with explicit versioning and
compatibility guarantees) will be provided independently for users who need
a durable, interoperable representation. The parse cache is not that — it
is purely an acceleration mechanism tied to a specific TP build.
Cache key
The cache is identified by:
Where
trace_identityis:stat())File.name+File.size+File.lastModifiedos.stat())This is fast to compute (no file content hashing) and sufficient for
practical invalidation. The chance of a false cache hit (different trace
content with identical name + size + mtime) is negligible.
"Relevant global flags" are those that affect parsing behavior:
--full-sort,--no-ftrace-raw,--crop-track-events, etc.The inclusion of
tp_versionin the cache key means that upgrading TPautomatically invalidates all existing caches. This is intentional — schema
changes between versions make old caches unsafe to load.
Cache location
~/.cache/perfetto/parse-cache/<hash>by default, overridable via--parse-cache-dir. The cache directory is created on first write.CLI:
--parse-cacheglobal flagtrace_processor_shell --parse-cache query -c "SELECT ..." trace.pbBehavior:
flags.
Parse()instead ofthe original trace. Skip to step 5.
Parse()as normal.thread via
ExportToArrow().terminating.
The background write means the first load has no added latency for queries.
The wait-on-exit means the cache is guaranteed to exist after the first
invocation completes.
CLI:
parse-cachesubcommandFor explicit cache management by human users:
RPC:
/parsewith trace identityTo support caching for RPC clients (UI, Python), the first
/parsecallgains an optional
trace_identityfield:Flow:
/parsechunk withtrace_identityset.skip_further_parse = true. Discard data from this and all subsequent/parsecalls.skip_further_parse = false. Continue accepting/parsechunks.notify_eof, if cache was missed, write cache in background.trace_identity: no caching, existingbehavior unchanged.
skip_further_parseand keep sending: shelldiscards bytes, everything still works.
This is fully backwards compatible in both directions.
Python API
Caching is configured via
TraceProcessorConfig:Implementation:
parse_cache=Truecauses the Python wrapper to pass--parse-cacheto the shell subprocess. The Python client also sendstrace_identity(fromos.stat()) on the first/parsecall so theshell can check its cache. If the response has
skip_further_parse = true,Python skips sending remaining chunks.
No explicit cache management API in Python. Users who want manual control
can use the CLI
parse-cachesubcommand.What is NOT cached
recomputed on top of the cached tables. This is expected and fast.
__intrinsic_trace_file,__intrinsic_trace_import_logs, and similar metadata tables are excludedfrom the cache.
stdin or generated programmatically), caching is silently skipped.
Disk space
The cache size is roughly comparable to the parsed table data, which can be
a significant fraction of the original trace size. Mitigations:
--parse-cacheflag orparse-cache create).Users make a conscious choice to spend disk space.
parse-cache infoshows cache sizes.parse-cache clear --allprovides easy cleanup.Parse cache written: 8.2 GB at ~/.cache/perfetto/parse-cache/a1b2c3Concurrency
rename. This prevents partial reads from concurrent TP instances.
write a cache. The last rename wins, which is fine since the content is
identical.
Architecture summary
TP core provides the primitives (
ExportToArrow, import viaParse). Theshell layer orchestrates caching. RPC clients provide trace identity
metadata. No caching logic in TP core or the RPC layer itself.
Alternatives considered
1. Cache in TP core
Add cache awareness to
TraceProcessordirectly (e.g., inNotifyEndOfFile()orConfig).Pro:
Con:
surprising and hard to control.
2. SQLite as cache format
Use the existing
ExportTraceToDatabase()as the cache format instead.Pro:
Con:
3. Automatic caching by default
Enable caching automatically without user opt-in.
Pro:
Con:
comparably sized cache silently.
4. Content hashing for cache key
Use SHA256 of the full trace content as the cache key instead of
path + size + mtime.
Pro:
Con:
hash is wasteful.
Open questions
(LRU)? Or is manual
parse-cache clearsufficient?parse-cache createsupport creating caches for multiple tracesat once (e.g.,
parse-cache create *.pb)?endpoint, or is
~/.cache/perfetto/parse-cache/always correct?💬 Discussion Guidelines:
All reactions