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