• 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--
16
17INCLUDE PERFETTO MODULE slices.with_context;
18
19-- Collect all GC slices. There's typically one enclosing slice but sometimes the
20-- CompactionPhase is outside the nesting and we need to include that.
21CREATE PERFETTO VIEW _gc_slice
22AS
23WITH concurrent AS (
24SELECT
25  id AS gc_id,
26  name AS gc_name,
27  LEAD(name) OVER (PARTITION BY track_id ORDER BY ts) AS compact_name,
28  LEAD(dur) OVER (PARTITION BY track_id ORDER BY ts) AS compact_dur,
29  ts AS gc_ts,
30  IIF(dur = -1, trace_end() - slice.ts, slice.dur) AS gc_dur,
31  ts,
32  dur,
33  tid,
34  utid,
35  pid,
36  upid,
37  thread_name,
38  process_name
39FROM thread_slice slice
40WHERE depth = 0
41) SELECT
42  gc_id,
43  gc_name,
44  ts AS gc_ts,
45  ts,
46  gc_dur + IIF(
47    compact_name = 'CompactionPhase' OR compact_name = 'Background concurrent copying GC',
48    compact_dur,
49    0) AS gc_dur,
50  gc_dur + IIF(
51    compact_name = 'CompactionPhase' OR compact_name = 'Background concurrent copying GC',
52    compact_dur,
53    0) AS dur,
54  utid,
55  tid,
56  upid,
57  pid,
58  thread_name,
59  process_name
60FROM concurrent WHERE gc_name GLOB '*concurrent*GC';
61
62-- Extract the heap counter into <ts, dur, upid>
63CREATE PERFETTO VIEW _gc_heap_counter
64AS
65SELECT
66  c.ts,
67  IFNULL(lead(c.ts) OVER (PARTITION BY track_id ORDER BY c.ts), trace_end()) - ts
68    AS dur,
69  process.upid,
70  CAST(c.value AS INT) AS value
71FROM counter c
72JOIN process_counter_track t
73  ON c.track_id = t.id
74INNER JOIN process
75  USING (upid)
76WHERE
77  t.name = 'Heap size (KB)';
78
79-- Find the last heap counter after the GC slice dur. This is the best effort to find the
80-- final heap size after GC. The algorithm is like so:
81-- 1. Merge end_ts of the GC events with the start_ts of the heap counters.
82-- 2. Find the heap counter value right after each GC event.
83CREATE PERFETTO VIEW _gc_slice_with_final_heap
84AS
85WITH
86  slice_and_heap AS (
87    SELECT upid, gc_id, gc_ts + gc_dur AS ts, NULL AS value FROM _gc_slice
88    UNION ALL
89    SELECT upid, NULL AS gc_id, ts, value FROM _gc_heap_counter
90  ),
91  next_heap AS (
92    SELECT *, lead(value) OVER (PARTITION BY upid ORDER BY ts) AS last_value FROM slice_and_heap
93  ),
94  slice_with_last_heap AS (
95    SELECT * FROM next_heap WHERE gc_id IS NOT NULL
96  )
97  SELECT _gc_slice.*, last_value FROM _gc_slice LEFT JOIN slice_with_last_heap USING (gc_id);
98
99-- Span join with all the other heap counters to find the overall min and max heap size.
100CREATE VIRTUAL TABLE _gc_slice_heap_sp
101USING
102  SPAN_JOIN(_gc_slice_with_final_heap PARTITIONED upid, _gc_heap_counter PARTITIONED upid);
103
104-- Aggregate the min and max heap across the GC event, taking into account the last heap size
105-- derived earlier.
106CREATE PERFETTO TABLE _gc_slice_heap
107AS
108SELECT
109  *,
110  CASE
111    WHEN gc_name GLOB '*young*' THEN 'young'
112    WHEN gc_name GLOB '*NativeAlloc*' THEN 'native_alloc'
113    WHEN gc_name GLOB '*Alloc*' THEN 'alloc'
114    WHEN gc_name GLOB '*CollectorTransition*' THEN 'collector_transition'
115    WHEN gc_name GLOB '*Explicit*' THEN 'explicit'
116    ELSE 'full'
117    END AS gc_type,
118  IIF(gc_name GLOB '*mark compact*', 1, 0) AS is_mark_compact,
119  MAX(MAX(value, last_value))/1e3 AS max_heap_mb,
120  MIN(MIN(value, last_value))/1e3 AS min_heap_mb
121FROM _gc_slice_heap_sp
122GROUP BY gc_id;
123
124-- Span join GC events with thread states to breakdown the time spent.
125CREATE VIRTUAL TABLE _gc_slice_heap_thread_state_sp
126USING
127  SPAN_JOIN(thread_state PARTITIONED utid, _gc_slice_heap PARTITIONED utid);
128
129-- All Garbage collection events with a breakdown of the time spent and heap reclaimed.
130CREATE PERFETTO TABLE android_garbage_collection_events (
131  -- Tid of thread running garbage collection.
132  tid INT,
133  -- Pid of process running garbage collection.
134  pid INT,
135  -- Utid of thread running garbage collection.
136  utid INT,
137  -- Upid of process running garbage collection.
138  upid INT,
139  -- Name of thread running garbage collection.
140  thread_name INT,
141  -- Name of process running garbage collection.
142  process_name INT,
143  -- Type of garbage collection.
144  gc_type STRING,
145  -- Whether gargage collection is mark compact or copying.
146  is_mark_compact INT,
147  -- MB reclaimed after garbage collection.
148  reclaimed_mb INT,
149  -- Minimum heap size in MB during garbage collection.
150  min_heap_mb INT,
151  -- Maximum heap size in MB during garbage collection.
152  max_heap_mb INT,
153  -- Garbage collection id.
154  gc_id INT,
155  -- Garbage collection timestamp.
156  gc_ts INT,
157  -- Garbage collection wall duration.
158  gc_dur INT,
159  -- Garbage collection duration spent executing on CPU.
160  gc_running_dur INT,
161  -- Garbage collection duration spent waiting for CPU.
162  gc_runnable_dur INT,
163  -- Garbage collection duration spent waiting in the Linux kernel on IO.
164  gc_unint_io_dur INT,
165  -- Garbage collection duration spent waiting in the Linux kernel without IO.
166  gc_unint_non_io_dur INT,
167    -- Garbage collection duration spent waiting in interruptible sleep.
168  gc_int_dur INT
169  )
170AS
171WITH
172  agg_events AS (
173    SELECT
174      tid,
175      pid,
176      utid,
177      upid,
178      thread_name,
179      process_name,
180      gc_type,
181      is_mark_compact,
182      gc_id,
183      gc_ts,
184      gc_dur,
185      SUM(dur) AS dur,
186      max_heap_mb - min_heap_mb AS reclaimed_mb,
187      min_heap_mb,
188      max_heap_mb,
189      state,
190      io_wait
191    FROM _gc_slice_heap_thread_state_sp
192    GROUP BY gc_id, state, io_wait
193  )
194SELECT
195  tid,
196  pid,
197  utid,
198  upid,
199  thread_name,
200  process_name,
201  gc_type,
202  is_mark_compact,
203  reclaimed_mb,
204  min_heap_mb,
205  max_heap_mb,
206  gc_id,
207  gc_ts,
208  gc_dur,
209  SUM(IIF(state = 'Running', dur, 0)) AS gc_running_dur,
210  SUM(IIF(state = 'R' OR state = 'R+', dur, 0)) AS gc_runnable_dur,
211  SUM(IIF(state = 'D' AND io_wait = 1, dur, 0)) AS gc_unint_io_dur,
212  SUM(IIF(state = 'D' AND io_wait != 1, dur, 0)) AS gc_unint_non_io_dur,
213  SUM(IIF(state = 'S', dur, 0)) AS gc_int_dur
214FROM agg_events
215GROUP BY gc_id;
216