• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1--
2-- Copyright 2024 The Android Open Source Project
3--
4-- Licensed under the Apache License, Version 2.0 (the "License");
5-- you may not use this file except in compliance with the License.
6-- You may obtain a copy of the License at
7--
8--     https://www.apache.org/licenses/LICENSE-2.0
9--
10-- Unless required by applicable law or agreed to in writing, software
11-- distributed under the License is distributed on an "AS IS" BASIS,
12-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-- See the License for the specific language governing permissions and
14-- limitations under the License.
15
16INCLUDE PERFETTO MODULE android.startup.startups;
17
18INCLUDE PERFETTO MODULE android.frames.timeline;
19
20INCLUDE PERFETTO MODULE slices.with_context;
21
22CREATE PERFETTO VIEW _startups_with_upid AS
23WITH
24  joined_with_processes AS (
25    SELECT
26      s.*,
27      p.upid
28    FROM android_startups AS s
29    LEFT JOIN android_startup_processes AS p
30      USING (startup_id)
31  ),
32  fallback AS (
33    SELECT
34      s.*,
35      upid
36    FROM android_startups AS s
37    JOIN process AS p
38      ON (
39        p.name GLOB s.package
40      )
41  )
42SELECT
43  j.startup_id,
44  j.ts,
45  j.ts_end,
46  j.dur,
47  j.package,
48  j.startup_type,
49  coalesce(j.upid, f.upid) AS upid
50FROM joined_with_processes AS j
51LEFT JOIN fallback AS f
52  ON (
53    j.upid IS NULL AND j.startup_id = f.startup_id
54  );
55
56-- Get Time To Initial Display of the startup calculated as time between the
57-- startup started and the first frame that was started by Choreographer on the
58-- UI thread of the startup finished drawing.
59-- TTID (https://developer.android.com/topic/performance/vitals/launch-time#time-initial)
60-- Googlers: see go/android-performance-metrics-glossary for details.
61CREATE PERFETTO TABLE _ttid AS
62WITH
63  frames_with_upid AS (
64    SELECT
65      f.*
66    FROM android_frames AS f
67    JOIN thread AS t
68      ON (
69        f.ui_thread_utid = t.utid
70      )
71  ),
72  -- First `DrawFrame` on Render Thread after the startup.
73  first_frame_for_startup AS (
74    SELECT
75      startup_id,
76      frame_id,
77      s.ts AS startup_ts,
78      draw_frame_id,
79      s.upid
80    FROM _startups_with_upid AS s
81    JOIN frames_with_upid AS f
82      ON (
83        s.upid = f.upid AND s.ts <= f.ts
84      )
85    GROUP BY
86      startup_id
87    ORDER BY
88      startup_id,
89      f.ts
90  )
91SELECT
92  startup_id,
93  frame_id,
94  draw_frame_id,
95  ts + dur - startup_ts AS ttid,
96  upid
97FROM first_frame_for_startup
98JOIN slice
99  ON (
100    slice.id = draw_frame_id
101  );
102
103-- Get Time To Full Display of the startup calculated as time between the
104-- startup started and the first frame that was started by Choreographer after
105-- or containing the `reportFullyDrawn()` slice on the UI thread of the startup
106-- finished drawing.
107-- TTFD (https://developer.android.com/topic/performance/vitals/launch-time#retrieve-TTFD)
108-- Googlers: see go/android-performance-metrics-glossary for details.
109CREATE PERFETTO TABLE _ttfd AS
110-- First `reportFullyDrawn` slice for each startup.
111WITH
112  first_report_fully_drawn_for_startup AS (
113    SELECT
114      startup_id,
115      s.ts AS startup_ts,
116      t.ts AS report_fully_drawn_ts,
117      t.utid,
118      s.upid
119    FROM _startups_with_upid AS s
120    JOIN thread_slice AS t
121      ON (
122        s.upid = t.upid AND t.ts >= s.ts
123      )
124    WHERE
125      name GLOB "reportFullyDrawn*" AND t.is_main_thread = 1
126    GROUP BY
127      startup_id
128    ORDER BY
129      startup_id,
130      t.ts
131  ),
132  -- After the first `reportFullyDrawn` find the first `Choreographer#DoFrame` on
133  -- the UI thread and it's first `DrawFrame` on Render Thread.
134  first_frame_after_report_for_startup AS (
135    SELECT
136      startup_id,
137      frame_id,
138      startup_ts,
139      draw_frame_id,
140      s.upid
141    FROM first_report_fully_drawn_for_startup AS s
142    JOIN android_frames AS f
143      ON (
144        s.utid = f.ui_thread_utid
145        -- We are looking for the first DrawFrame that was started by the first
146        -- "Choreographer#DoFrame" on UI thread after or containing
147        -- reportFullyDrawn. In Android UIs, it's common to have UI code happen
148        -- either before a frame, or during it, and generally non-trivial amounts
149        -- of "update UI model" code doesn't try to differentiate these. We account
150        -- for both of these by looking for the first UI slice that ends after the
151        -- "reportFullyDrawnSlice" begins.
152        AND report_fully_drawn_ts < (
153          f.ts + f.dur
154        )
155      )
156    GROUP BY
157      startup_id
158    ORDER BY
159      startup_id,
160      f.ts
161  )
162-- Get TTFD as the difference between the start of the startup and the end of
163-- `DrawFrame` slice we previously found.
164SELECT
165  startup_id,
166  frame_id,
167  draw_frame_id,
168  ts + dur - startup_ts AS ttfd,
169  upid
170FROM first_frame_after_report_for_startup
171JOIN slice
172  ON (
173    slice.id = draw_frame_id
174  );
175
176-- Startup metric defintions, which focus on the observable time range:
177-- TTID - Time To Initial Display
178-- * https://developer.android.com/topic/performance/vitals/launch-time#time-initial
179-- * end of first RenderThread.DrawFrame - bindApplication
180-- TTFD - Time To Full Display
181-- * https://developer.android.com/topic/performance/vitals/launch-time#retrieve-TTFD
182-- * end of next RT.DrawFrame, after reportFullyDrawn called - bindApplication
183-- Googlers: see go/android-performance-metrics-glossary for details.
184CREATE PERFETTO TABLE android_startup_time_to_display (
185  -- Startup id.
186  startup_id LONG,
187  -- Time to initial display (TTID)
188  time_to_initial_display LONG,
189  -- Time to full display (TTFD)
190  time_to_full_display LONG,
191  -- `android_frames.frame_id` of frame for initial display
192  ttid_frame_id LONG,
193  -- `android_frames.frame_id` of frame for full display
194  ttfd_frame_id LONG,
195  -- `process.upid` of the startup
196  upid JOINID(process.id)
197) AS
198SELECT
199  startup_id,
200  ttid AS time_to_initial_display,
201  ttfd AS time_to_full_display,
202  _ttid.frame_id AS ttid_frame_id,
203  _ttfd.frame_id AS ttfd_frame_id,
204  _ttid.upid
205FROM android_startups
206LEFT JOIN _ttid
207  USING (startup_id)
208LEFT JOIN _ttfd
209  USING (startup_id);
210