Query ProfilingManager profiles

Querying ProfilingManager profiles is similar to querying regular Perfetto profiles. Therefore, review Getting Started with PerfettoSQL for a guide on how to query profiles.

An important distinction between regular Perfetto traces and ProfilingManager traces is that ProfilingManager traces pass through a trace redactor. This redactor removes information about other processes unrelated to your app for privacy reasons.

Some queries from the Perfetto standard library are not usable on redacted traces. This is because ProfilingManager only collects profiling data for your app, not other processes. As a result, the queries you can use with ProfilingManager are a smaller set than those for full system profiles recorded using local Perfetto.

Even though the querying space is reduced, you can still use many PerfettoSQL queries and tables from the Perfetto Standard Library as-is, so we encourage you to try them.

We also recommend that you review Analyzing Android Traces to find ready-to-use queries that provide useful performance data without modification.

ProfilingManager sample queries

To simplify the querying journey, this section provides a list of queries that work with ProfilingManager. You can use these queries directly or as examples to build other queries.

Find the most duplicated slices

This query finds repeated slices in a trace and sorts them by how often they appear, showing the most duplicated ones first.

Finding duplicated work is a common way to find unnecessary work in a trace.

-- You only need to call this once in the session to create the function
DROPTABLEIFEXISTSfind_duplicates;
CREATEPERFETTOFUNCTIONfind_duplicates(patternSTRING)RETURNS
TABLE(nameSTRING,count_sliceLONG)ASSELECTname,COUNT(dur)ascount_sliceFROMsliceWHEREnameGLOB$patternGROUPBYnameHAVINGCOUNT(name)>=2ORDERBYcount_sliceDESC;
-- Subsequent calls can just use the function to find dupes
SELECT*FROMfind_duplicates('*Text*')

Jank queries

Find slow frames

This query finds frames where your app takes too long to generate a frame, assuming an expected frame rate of 60 Hz (16.6 ms). The dur is set to 16,660,000 because slice durations in Perfetto tables are stored in nanoseconds.

INCLUDEPERFETTOmoduleandroid.frames.timeline;
SELECT*FROMandroid_framesWHEREdur > 16660000;

Find jank-causing frames

INCLUDEPERFETTOmoduleandroid.frames.timeline;
SELECT*FROMactual_frame_timeline_sliceWHEREjank_type='App Deadline Missed';

This query is useful to find locations where jank occurs in the trace because the app takes too long to generate a frame. This means that the UI thread failed to generate a frame. Under extreme circumstances, this could precede an ANR.

Find most duplicated objects

You can also query memory-related profiles, such as heap dumps, to perform more complex memory analyses.

INCLUDEPERFETTOMODULEandroid.memory.heap_graph.heap_graph_class_aggregation;
SELECT*FROMandroid_heap_graph_class_aggregationWHEREobj_count>=2
ORDERBYobj_countDESCLIMIT100

This query returns the top 100 duplicated objects. This can help you find objects that are instantiated multiple times, which might reveal opportunities for caching them or identify unintended duplicates.

Cold startup latency

You can also query for startups. This section provides a more elaborate query to estimate cold startup time in a trace.

-- This function finds slices that match the given GLOB $pattern
CREATEORREPLACEFUNCTIONfind_slices(patternSTRING)RETURNS
TABLE(nameSTRING,tsLONG,durLONG)AS
SELECTname,ts,durFROMsliceWHEREnameGLOB$pattern;
-- This function generates a slice that starts at $startSlicePattern and finishes at the slice matched by $endSlicePattern. If $inclusive is true, then the end slice dur will be added, otherwise, the end slice start time will be used.
CREATEORREPLACEPERFETTOFUNCTIONgenerate_start_to_end_slices(startSlicePatternSTRING,endSlicePatternSTRING,inclusiveBOOL)RETURNS
TABLE(nameSTRING,tsLONG,durLONG)AS
SELECTname,ts,MIN(startToEndDur)asdur
FROM
(SELECTS.nameasname,S.tsasts,E.ts+IIF($inclusive,E.dur,0)-S.tsasstartToEndDur
FROMfind_slices($startSlicePattern)asSCROSSJOINfind_slices($endSlicePattern)asE
WHEREstartToEndDur > 0)
GROUPBYname,ts;
-- Using these functions we can estimate cold startup time by generating a slice between bindApplication and first frame.
SELECT*fromgenerate_start_to_end_slices('bindApplication','*Choreographer#doFrame [0-9]*',true)

This query generates a slice that represents the time between two slices that define the startup time: bindApplication (typically found at the start of a cold app launch) and the first Choreographer#doFrame slice (the first generated frame). This metric effectively estimates cold startup TTFF (time to first frame).

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2025年12月20日 UTC.