• 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 intervals.intersect;
17
18INCLUDE PERFETTO MODULE wattson.curves.estimates;
19
20-- Get slice info of threads/processes
21CREATE PERFETTO TABLE _thread_process_slices AS
22SELECT
23  sched.ts,
24  sched.dur,
25  sched.cpu,
26  thread.utid,
27  thread.upid
28FROM thread
29JOIN sched
30  USING (utid)
31WHERE
32  dur > 0;
33
34-- Helper macro so Perfetto tables can be used with interval intersect
35CREATE PERFETTO MACRO _ii_table(
36    tab TableOrSubquery
37)
38RETURNS TableOrSubquery AS
39(
40  SELECT
41    _auto_id AS id,
42    *
43  FROM $tab
44);
45
46-- Get slices only where there is transition from deep idle to active
47CREATE PERFETTO TABLE _idle_exits AS
48SELECT
49  ts,
50  dur,
51  cpu,
52  idle
53FROM _adjusted_deep_idle
54WHERE
55  idle = -1 AND dur > 0;
56
57-- Gets the slices where the CPU transitions from deep idle to active, and the
58-- associated thread that causes the idle exit
59CREATE PERFETTO TABLE _idle_w_threads AS
60WITH
61  _ii_idle_threads AS (
62    SELECT
63      ii.ts,
64      ii.dur,
65      ii.cpu,
66      threads.utid,
67      threads.upid,
68      id_1 AS idle_group
69    FROM _interval_intersect!(
70    (
71      _ii_table!(_thread_process_slices),
72      _ii_table!(_idle_exits)
73    ),
74    (cpu)
75  ) AS ii
76    JOIN _thread_process_slices AS threads
77      ON threads._auto_id = id_0
78  ),
79  -- Since sorted by time, MIN() is fast aggregate function that will return the
80  -- first time slice, which will be the utid = 0 slice immediately succeeding the
81  -- idle to active transition, and immediately preceding the active thread
82  first_swapper_slice AS (
83    SELECT
84      ts,
85      dur,
86      cpu,
87      idle_group,
88      min(ts) AS min
89    FROM _ii_idle_threads
90    GROUP BY
91      idle_group
92  ),
93  -- MIN() here will give the first active thread immediately succeeding the idle
94  -- to active transition slice, which means this the the thread that causes the
95  -- idle exit
96  first_non_swapper_slice AS (
97    SELECT
98      idle_group,
99      utid,
100      upid,
101      min(ts) AS min,
102      min(ts) + dur AS next_ts
103    FROM _ii_idle_threads
104    WHERE
105      NOT utid IN (
106        SELECT
107          utid
108        FROM thread
109        WHERE
110          is_idle
111      )
112    GROUP BY
113      idle_group
114  ),
115  -- MAX() here will give the last time slice in the group. This will be the
116  -- utid = 0 slice immediately preceding the active to idle transition.
117  last_swapper_slice AS (
118    SELECT
119      ts,
120      dur,
121      cpu,
122      idle_group,
123      max(ts) AS min
124    FROM _ii_idle_threads
125    GROUP BY
126      idle_group
127  )
128SELECT
129  swapper_info.ts,
130  swapper_info.dur,
131  swapper_info.cpu,
132  thread_info.utid,
133  thread_info.upid
134FROM first_non_swapper_slice AS thread_info
135JOIN first_swapper_slice AS swapper_info
136  USING (idle_group)
137UNION ALL
138-- Adds the last slice to idle transition attribution IF this is a singleton
139-- thread wakeup. This is true if there is only one thread between swapper idle
140-- exits/wakeups. For example, groups with order of swapper, thread X, swapper
141-- will be included. Entries that have multiple thread between swappers, such as
142-- swapper, thread X, thread Y, swapper will not be included.
143SELECT
144  swapper_info.ts,
145  swapper_info.dur,
146  swapper_info.cpu,
147  thread_info.utid,
148  thread_info.upid
149FROM first_non_swapper_slice AS thread_info
150JOIN last_swapper_slice AS swapper_info
151  USING (idle_group)
152WHERE
153  ts = next_ts;
154
155-- Interval intersect with the estimate power track, so that each slice can be
156-- attributed to the power of the CPU in that time duration
157CREATE PERFETTO TABLE _idle_transition_cost AS
158SELECT
159  ii.ts,
160  ii.dur,
161  threads.cpu,
162  threads.utid,
163  threads.upid,
164  CASE threads.cpu
165    WHEN 0
166    THEN power.cpu0_mw
167    WHEN 1
168    THEN power.cpu1_mw
169    WHEN 2
170    THEN power.cpu2_mw
171    WHEN 3
172    THEN power.cpu3_mw
173    WHEN 4
174    THEN power.cpu4_mw
175    WHEN 5
176    THEN power.cpu5_mw
177    WHEN 6
178    THEN power.cpu6_mw
179    WHEN 7
180    THEN power.cpu7_mw
181    ELSE 0
182  END AS estimated_mw
183FROM _interval_intersect!(
184  (
185    _ii_table!(_idle_w_threads),
186    _ii_table!(_system_state_mw)
187  ),
188  ()
189) AS ii
190JOIN _idle_w_threads AS threads
191  ON threads._auto_id = id_0
192JOIN _system_state_mw AS power
193  ON power._auto_id = id_1;
194
195-- Macro for easily filtering idle attribution to a specified time window. This
196-- information can then further be filtered by specific CPU and GROUP BY on
197-- either utid or upid
198CREATE PERFETTO FUNCTION _filter_idle_attribution(
199    ts TIMESTAMP,
200    dur LONG
201)
202RETURNS TABLE (
203  idle_cost_mws LONG,
204  utid JOINID(thread.id),
205  upid JOINID(process.id),
206  cpu JOINID(cpu.id)
207) AS
208-- Give the negative sum of idle costs to the swapper thread, which by
209-- definition has a utid = 0, upid = 0, and by definition will not be defined,
210-- so need to UNION to manually add swapper thread
211WITH
212  base AS (
213    SELECT
214      cost.estimated_mw * cost.dur / 1e9 AS idle_cost_mws,
215      cost.utid,
216      cost.upid,
217      cost.cpu
218    FROM _interval_intersect_single!(
219    $ts, $dur, _ii_table!(_idle_transition_cost)
220  ) AS ii
221    JOIN _idle_transition_cost AS cost
222      ON cost._auto_id = id
223  )
224SELECT
225  idle_cost_mws,
226  utid,
227  upid,
228  cpu
229FROM base
230UNION ALL
231SELECT
232  -1 * sum(idle_cost_mws) AS idle_cost_mws,
233  0 AS utid,
234  0 AS upid,
235  cpu
236FROM base
237GROUP BY
238  cpu;
239