• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1-- Copyright 2023 The Chromium Authors
2-- Use of this source code is governed by a BSD-style license that can be
3-- found in the LICENSE file.
4
5-- Find causes for CPUs powering up.
6--
7-- The scripts below analyse traces with the following tracing options
8-- enabled:
9--
10--  - Linux kernel:
11---    "power/*", "sched/*", "task/*",
12--  - Chromium:
13--      "toplevel", "toplevel.flow".
14
15-- Noteworthy tables:
16--
17--   chrome_cpu_power_first_toplevel_slice_after_powerup :: The top-level
18--      slices that ran after a CPU power-up.
19
20-- The CPU power transitions in the trace.
21-- Power states are encoded as non-negative integers, with zero representing
22-- full-power operation and positive values representing increasingly deep
23-- sleep states.
24--
25-- On ARM systems, power state 1 represents the WFI (Wait For Interrupt) sleep
26-- state that the CPU enters while idle.
27CREATE PERFETTO VIEW chrome_cpu_power_slice(
28  -- The timestamp at the start of the slice.
29  ts TIMESTAMP,
30  -- The duration of the slice.
31  dur DURATION,
32  -- The CPU on which the transition occurred
33  cpu LONG,
34  -- The power state that the CPU was in at time 'ts' for duration 'dur'.
35  power_state LONG,
36  -- The power state that the CPU was previously in.
37  previous_power_state LONG,
38  -- A unique ID for the CPU power-up.
39  powerup_id LONG
40) AS
41  WITH cpu_power_states AS (
42    SELECT
43      c.id AS id,
44      cct.cpu AS cpu,
45      c.ts,
46      -- Encode the 'value' field as a power state.
47      cast_int!((CASE c.value WHEN 4294967295 THEN 0 ELSE c.value + 1 END)) AS power_state
48    FROM counter AS c
49    JOIN cpu_counter_track AS cct
50      ON c.track_id = cct.id
51    WHERE cct.name = 'cpuidle'
52  )
53  SELECT *
54  FROM (
55    SELECT
56      ts,
57      LEAD(ts) OVER (PARTITION BY cpu ORDER BY ts ASC) - ts
58        AS dur,
59      cpu,
60      power_state,
61      LAG(power_state) OVER (PARTITION BY cpu ORDER BY ts ASC)
62        AS previous_power_state,
63      id AS powerup_id
64    FROM cpu_power_states
65  )
66  WHERE dur IS NOT NULL
67    AND previous_power_state IS NOT NULL
68    AND power_state = 0                      -- Track full-power states.
69    AND power_state != previous_power_state  -- Skip missing spans.
70    ORDER BY ts ASC;
71
72-- We do not want scheduler slices with utid = 0 (the 'swapper' kernel thread).
73CREATE PERFETTO VIEW _cpu_power_valid_sched_slice AS
74  SELECT *
75  FROM sched_slice
76  WHERE utid != 0;
77
78-- Join scheduler slices with the spans with CPU power slices.
79--
80-- There multiple scheduler slices could fall into one CPU power slice.
81--
82---  CPU Power:
83--   |----------------------------|....................|---------|
84--   A       <cpu active>         B     <cpu idling>   C         D
85
86--   Scheduler slices on that CPU:
87--     |-----T1-----| |....T2....|                      |---T3--|
88--     E            F G          H                      I       J
89--
90-- Here threads T1 and T2 executed in CPU power slice [A,B].  The
91-- time between F and G represents time between threads in the kernel.
92CREATE VIRTUAL TABLE _cpu_power_and_sched_slice
93USING
94  SPAN_JOIN(chrome_cpu_power_slice PARTITIONED cpu,
95            _cpu_power_valid_sched_slice PARTITIONED cpu);
96
97-- The Linux scheduler slices that executed immediately after a
98-- CPU power up.
99CREATE PERFETTO TABLE chrome_cpu_power_first_sched_slice_after_powerup(
100  -- The timestamp at the start of the slice.
101  ts TIMESTAMP,
102  -- The duration of the slice.
103  dur DURATION,
104  -- The cpu on which the slice executed.
105  cpu LONG,
106  -- Id for the sched_slice table.
107  sched_id LONG,
108  -- Unique id for the thread that ran within the slice.
109  utid LONG,
110  -- The CPU's power state before this slice.
111  previous_power_state LONG,
112  -- A unique ID for the CPU power-up.
113  powerup_id LONG
114) AS
115SELECT
116  ts,
117  dur,
118  cpu,
119  id AS sched_id,
120  utid,
121  previous_power_state,
122  powerup_id
123FROM _cpu_power_and_sched_slice
124WHERE power_state = 0     -- Power-ups only.
125GROUP BY cpu, powerup_id
126HAVING ts = MIN(ts)       -- There will only be one MIN sched slice
127                          -- per CPU power up.
128ORDER BY ts ASC;
129
130-- A view joining thread tracks and top-level slices.
131--
132-- This view is intended to be intersected by time with the scheduler
133-- slices scheduled after a CPU power up.
134--
135--   utid      Thread unique id.
136--   slice_id  The slice_id for the top-level slice.
137--   ts        Starting timestamp for the slice.
138--   dur       The duration for the slice.
139CREATE PERFETTO VIEW _cpu_power_thread_and_toplevel_slice AS
140  SELECT
141    t.utid AS utid,
142    s.id AS slice_id,
143    s.ts,
144    s.dur
145  FROM slice AS s
146  JOIN thread_track AS t
147    ON s.track_id = t.id
148  WHERE s.depth = 0   -- Top-level slices only.
149  ORDER BY ts ASC;
150
151CREATE VIRTUAL TABLE _chrome_cpu_power_post_powerup_slice_sj
152USING
153  SPAN_JOIN(chrome_cpu_power_first_sched_slice_after_powerup PARTITIONED utid,
154            _cpu_power_thread_and_toplevel_slice PARTITIONED utid);
155
156-- A table holding the slices that executed within the scheduler
157-- slice that ran on a CPU immediately after power-up.
158CREATE PERFETTO TABLE chrome_cpu_power_post_powerup_slice(
159  -- Timestamp of the resulting slice
160  ts TIMESTAMP,
161  -- Duration of the slice.
162  dur DURATION,
163  -- The CPU the sched slice ran on.
164  cpu LONG,
165  -- Unique thread id for the slice.
166  utid LONG,
167  -- 'id' field from the sched_slice table.
168  sched_id LONG,
169  -- Id of the top-level slice for this (sched) slice.
170  slice_id LONG,
171  -- Previous power state.
172  previous_power_state LONG,
173  -- Id of the powerup.
174  powerup_id LONG
175) AS
176SELECT * FROM _chrome_cpu_power_post_powerup_slice_sj;
177
178-- The first top-level slice that ran after a CPU power-up.
179CREATE PERFETTO VIEW chrome_cpu_power_first_toplevel_slice_after_powerup(
180  -- ID of the slice in the slice table.
181  slice_id LONG,
182  -- The power state of the CPU prior to power-up.
183  previous_power_state LONG
184) AS
185  SELECT slice_id, previous_power_state
186  FROM chrome_cpu_power_post_powerup_slice
187  GROUP BY cpu, powerup_id
188  HAVING ts = MIN(ts)
189  ORDER BY ts ASC;
190