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 INT, 30 -- The duration of the slice. 31 dur INT, 32 -- The CPU on which the transition occurred 33 cpu INT, 34 -- The power state that the CPU was in at time 'ts' for duration 'dur'. 35 power_state INT, 36 -- The power state that the CPU was previously in. 37 previous_power_state INT, 38 -- A unique ID for the CPU power-up. 39 powerup_id INT 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((CASE c.value WHEN 4294967295 THEN 0 ELSE c.value + 1 END) 48 AS INT) AS power_state 49 FROM counter AS c 50 JOIN cpu_counter_track AS cct 51 ON c.track_id = cct.id 52 WHERE cct.name = 'cpuidle' 53 ) 54 SELECT * 55 FROM ( 56 SELECT 57 ts, 58 LEAD(ts) OVER (PARTITION BY cpu ORDER BY ts ASC) - ts 59 AS dur, 60 cpu, 61 power_state, 62 LAG(power_state) OVER (PARTITION BY cpu ORDER BY ts ASC) 63 AS previous_power_state, 64 id AS powerup_id 65 FROM cpu_power_states 66 ) 67 WHERE dur IS NOT NULL 68 AND previous_power_state IS NOT NULL 69 AND power_state = 0 -- Track full-power states. 70 AND power_state != previous_power_state -- Skip missing spans. 71 ORDER BY ts ASC; 72 73-- We do not want scheduler slices with utid = 0 (the 'swapper' kernel thread). 74CREATE PERFETTO VIEW internal_cpu_power_valid_sched_slice AS 75 SELECT * 76 FROM sched_slice 77 WHERE utid != 0; 78 79-- Join scheduler slices with the spans with CPU power slices. 80-- 81-- There multiple scheduler slices could fall into one CPU power slice. 82-- 83--- CPU Power: 84-- |----------------------------|....................|---------| 85-- A <cpu active> B <cpu idling> C D 86 87-- Scheduler slices on that CPU: 88-- |-----T1-----| |....T2....| |---T3--| 89-- E F G H I J 90-- 91-- Here threads T1 and T2 executed in CPU power slice [A,B]. The 92-- time between F and G represents time between threads in the kernel. 93CREATE VIRTUAL TABLE internal_cpu_power_and_sched_slice 94USING 95 SPAN_JOIN(chrome_cpu_power_slice PARTITIONED cpu, 96 internal_cpu_power_valid_sched_slice PARTITIONED cpu); 97 98-- The Linux scheduler slices that executed immediately after a 99-- CPU power up. 100CREATE PERFETTO TABLE chrome_cpu_power_first_sched_slice_after_powerup( 101 -- The timestamp at the start of the slice. 102 ts INT, 103 -- The duration of the slice. 104 dur INT, 105 -- The cpu on which the slice executed. 106 cpu INT, 107 -- Id for the sched_slice table. 108 sched_id INT, 109 -- Unique id for the thread that ran within the slice. 110 utid INT, 111 -- The CPU's power state before this slice. 112 previous_power_state INT, 113 -- A unique ID for the CPU power-up. 114 powerup_id INT 115) AS 116SELECT 117 ts, 118 dur, 119 cpu, 120 id AS sched_id, 121 utid, 122 previous_power_state, 123 powerup_id 124FROM internal_cpu_power_and_sched_slice 125WHERE power_state = 0 -- Power-ups only. 126GROUP BY cpu, powerup_id 127HAVING ts = MIN(ts) -- There will only be one MIN sched slice 128 -- per CPU power up. 129ORDER BY ts ASC; 130 131-- A view joining thread tracks and top-level slices. 132-- 133-- This view is intended to be intersected by time with the scheduler 134-- slices scheduled after a CPU power up. 135-- 136-- utid Thread unique id. 137-- slice_id The slice_id for the top-level slice. 138-- ts Starting timestamp for the slice. 139-- dur The duration for the slice. 140CREATE PERFETTO VIEW internal_cpu_power_thread_and_toplevel_slice AS 141 SELECT 142 t.utid AS utid, 143 s.id AS slice_id, 144 s.ts, 145 s.dur 146 FROM slice AS s 147 JOIN thread_track AS t 148 ON s.track_id = t.id 149 WHERE s.depth = 0 -- Top-level slices only. 150 ORDER BY ts ASC; 151 152-- A table holding the slices that executed within the scheduler 153-- slice that ran on a CPU immediately after power-up. 154-- 155-- @column ts Timestamp of the resulting slice 156-- @column dur Duration of the slice. 157-- @column cpu The CPU the sched slice ran on. 158-- @column utid Unique thread id for the slice. 159-- @column sched_id 'id' field from the sched_slice table. 160-- @column type From the sched_slice table, always 'sched_slice'. 161-- @column end_state The ending state for the sched_slice 162-- @column priority The kernel thread priority 163-- @column slice_id Id of the top-level slice for this (sched) slice. 164CREATE VIRTUAL TABLE chrome_cpu_power_post_powerup_slice 165USING 166 SPAN_JOIN(chrome_cpu_power_first_sched_slice_after_powerup PARTITIONED utid, 167 internal_cpu_power_thread_and_toplevel_slice PARTITIONED utid); 168 169-- The first top-level slice that ran after a CPU power-up. 170CREATE PERFETTO VIEW chrome_cpu_power_first_toplevel_slice_after_powerup( 171 -- ID of the slice in the slice table. 172 slice_id INT, 173 -- The power state of the CPU prior to power-up. 174 previous_power_state INT 175) AS 176 SELECT slice_id, previous_power_state 177 FROM chrome_cpu_power_post_powerup_slice 178 GROUP BY cpu, powerup_id 179 HAVING ts = MIN(ts) 180 ORDER BY ts ASC; 181