1-- Copyright 2022 The Android Open Source Project 2-- 3-- Licensed under the Apache License, Version 2.0 (the "License"); 4-- you may not use this file except in compliance with the License. 5-- You may obtain a copy of the License at 6-- 7-- https://www.apache.org/licenses/LICENSE-2.0 8-- 9-- Unless required by applicable law or agreed to in writing, software 10-- distributed under the License is distributed on an "AS IS" BASIS, 11-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12-- See the License for the specific language governing permissions and 13-- limitations under the License. 14 15-- Find causes for CPUs powering up. 16-- 17-- The scripts below analyse traces with the following tracing options 18-- enabled: 19-- 20-- - Linux kernel: 21--- "power/*", "sched/*", "task/*", 22-- - Chromium: 23-- "toplevel", "toplevel.flow". 24 25-- Noteworthy tables: 26-- 27-- chrome_cpu_power_first_toplevel_slice_after_powerup :: The top-level 28-- slices that ran after a CPU power-up. 29 30-- The CPU power transitions in the trace. 31-- 32-- @column ts The timestamp at the start of the slice. 33-- @column dur The duration of the slice. 34-- @column cpu The CPU on which the transition occurred 35-- @column power_state The power state that the CPU was in at time 'ts' for 36-- duration 'dur'. 37-- @column previous_power_state The power state that the CPU was previously in. 38-- @column powerup_id A unique ID for the CPU power-up. 39-- 40-- Power states are encoded as non-negative integers, with zero representing 41-- full-power operation and positive values representing increasingly deep 42-- sleep states. 43-- 44-- On ARM systems, power state 1 represents the WFI (Wait For Interrupt) sleep 45-- state that the CPU enters while idle. 46CREATE VIEW chrome_cpu_power_slice AS 47 WITH cpu_power_states AS ( 48 SELECT 49 c.id AS id, 50 cct.cpu AS cpu, 51 c.ts, 52 -- Encode the 'value' field as a power state. 53 CAST((CASE c.value WHEN 4294967295 THEN 0 ELSE c.value + 1 END) 54 AS INT) AS power_state 55 FROM counter AS c 56 JOIN cpu_counter_track AS cct 57 ON c.track_id = cct.id 58 WHERE cct.name = 'cpuidle' 59 ) 60 SELECT * 61 FROM ( 62 SELECT 63 ts, 64 LEAD(ts) OVER (PARTITION BY cpu ORDER BY ts ASC) - ts 65 AS dur, 66 cpu, 67 power_state, 68 LAG(power_state) OVER (PARTITION BY cpu ORDER BY ts ASC) 69 AS previous_power_state, 70 id AS powerup_id 71 FROM cpu_power_states 72 ) 73 WHERE dur IS NOT NULL 74 AND previous_power_state IS NOT NULL 75 AND power_state = 0 -- Track full-power states. 76 AND power_state != previous_power_state -- Skip missing spans. 77 ORDER BY ts ASC; 78 79-- We do not want scheduler slices with utid = 0 (the 'swapper' kernel thread). 80CREATE VIEW internal_cpu_power_valid_sched_slice AS 81 SELECT * 82 FROM sched_slice 83 WHERE utid != 0; 84 85-- Join scheduler slices with the spans with CPU power slices. 86-- 87-- There multiple scheduler slices could fall into one CPU power slice. 88-- 89--- CPU Power: 90-- |----------------------------|....................|---------| 91-- A <cpu active> B <cpu idling> C D 92 93-- Scheduler slices on that CPU: 94-- |-----T1-----| |....T2....| |---T3--| 95-- E F G H I J 96-- 97-- Here threads T1 and T2 executed in CPU power slice [A,B]. The 98-- time between F and G represents time between threads in the kernel. 99CREATE VIRTUAL TABLE internal_cpu_power_and_sched_slice 100USING 101 SPAN_JOIN(chrome_cpu_power_slice PARTITIONED cpu, 102 internal_cpu_power_valid_sched_slice PARTITIONED cpu); 103 104-- The Linux scheduler slices that executed immediately after a 105-- CPU power up. 106-- 107-- @column ts The timestamp at the start of the slice. 108-- @column dur The duration of the slice. 109-- @column cpu The cpu on which the slice executed. 110-- @column sched_id Id for the sched_slice table. 111-- @column utid Unique id for the thread that ran within the slice. 112-- @column previous_power_state The CPU's power state before this slice. 113CREATE TABLE chrome_cpu_power_first_sched_slice_after_powerup AS 114 SELECT 115 ts, 116 dur, 117 cpu, 118 id AS sched_id, 119 utid, 120 previous_power_state, 121 powerup_id 122 FROM internal_cpu_power_and_sched_slice 123 WHERE power_state = 0 -- Power-ups only. 124 GROUP BY cpu, powerup_id 125 HAVING ts = MIN(ts) -- There will only be one MIN sched slice 126 -- per CPU power up. 127 ORDER BY ts ASC; 128 129-- A view joining thread tracks and top-level slices. 130-- 131-- This view is intended to be intersected by time with the scheduler 132-- slices scheduled after a CPU power up. 133-- 134-- utid Thread unique id. 135-- slice_id The slice_id for the top-level slice. 136-- ts Starting timestamp for the slice. 137-- dur The duration for the slice. 138CREATE VIEW internal_cpu_power_thread_and_toplevel_slice AS 139 SELECT 140 t.utid AS utid, 141 s.id AS slice_id, 142 s.ts, 143 s.dur 144 FROM slice AS s 145 JOIN thread_track AS t 146 ON s.track_id = t.id 147 WHERE s.depth = 0 -- Top-level slices only. 148 ORDER BY ts ASC; 149 150-- A table holding the slices that executed within the scheduler 151-- slice that ran on a CPU immediately after power-up. 152-- 153-- @column ts Timestamp of the resulting slice 154-- @column dur Duration of the slice. 155-- @column cpu The CPU the sched slice ran on. 156-- @column utid Unique thread id for the slice. 157-- @column sched_id 'id' field from the sched_slice table. 158-- @column type From the sched_slice table, always 'sched_slice'. 159-- @column end_state The ending state for the sched_slice 160-- @column priority The kernel thread priority 161-- @column slice_id Id of the top-level slice for this (sched) slice. 162CREATE VIRTUAL TABLE chrome_cpu_power_post_powerup_slice 163USING 164 SPAN_JOIN(chrome_cpu_power_first_sched_slice_after_powerup PARTITIONED utid, 165 internal_cpu_power_thread_and_toplevel_slice PARTITIONED utid); 166 167-- The first top-level slice that ran after a CPU power-up. 168-- 169-- @column slice_id ID of the slice in the slice table. 170-- @column previous_power_state The power state of the CPU prior to power-up. 171CREATE VIEW chrome_cpu_power_first_toplevel_slice_after_powerup AS 172 SELECT slice_id, previous_power_state 173 FROM chrome_cpu_power_post_powerup_slice 174 GROUP BY cpu, powerup_id 175 HAVING ts = MIN(ts) 176 ORDER BY ts ASC; 177