1-- 2-- Copyright 2019 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-- 16DROP VIEW IF EXISTS battery_view; 17CREATE VIEW battery_view AS 18SELECT 19 all_ts.ts as ts, 20 current_avg_ua, 21 capacity_percent, 22 charge_uah, 23 current_ua 24FROM ( 25 SELECT distinct(ts) AS ts 26 FROM counter c 27 JOIN counter_track t on c.track_id = t.id 28 WHERE name GLOB 'batt.*' 29) AS all_ts 30LEFT JOIN ( 31 SELECT ts, value AS current_avg_ua 32 FROM counter c 33 JOIN counter_track t on c.track_id = t.id 34 WHERE name='batt.current.avg_ua' 35) USING(ts) 36LEFT JOIN ( 37 SELECT ts, value AS capacity_percent 38 FROM counter c 39 JOIN counter_track t on c.track_id = t.id 40 WHERE name='batt.capacity_pct' 41) USING(ts) 42LEFT JOIN ( 43 SELECT ts, value AS charge_uah 44 FROM counter c 45 JOIN counter_track t on c.track_id = t.id 46 WHERE name='batt.charge_uah' 47) USING(ts) 48LEFT JOIN ( 49 SELECT ts, value AS current_ua 50 FROM counter c 51 JOIN counter_track t on c.track_id = t.id 52 WHERE name='batt.current_ua' 53) USING(ts) 54ORDER BY ts; 55 56DROP TABLE IF EXISTS android_batt_wakelocks_merged; 57CREATE TABLE android_batt_wakelocks_merged AS 58SELECT 59 MIN(ts) AS ts, 60 MAX(ts_end) AS ts_end 61FROM ( 62 SELECT 63 *, 64 SUM(new_group) OVER (ORDER BY ts) AS group_id 65 FROM ( 66 SELECT 67 ts, 68 ts + dur AS ts_end, 69 -- There is a new group if there was a gap before this wakelock. 70 -- i.e. the max end timestamp of all preceding wakelocks is before 71 -- the start timestamp of this one. 72 -- The null check is for the first row which is always a new group. 73 IFNULL( 74 MAX(ts + dur) OVER ( 75 ORDER BY ts 76 ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 77 ) < ts, 78 true 79 ) AS new_group 80 FROM slice 81 WHERE slice.name GLOB 'WakeLock *' AND dur != -1 82 ) 83) 84GROUP BY group_id; 85 86DROP TABLE IF EXISTS suspend_slice_; 87CREATE TABLE suspend_slice_ AS 88-- Traces from after b/70292203 was fixed have the action string so just look 89-- for it. 90SELECT 91 ts, 92 dur, 93 true as trustworthy 94FROM ( 95 SELECT 96 ts, 97 LEAD(ts) OVER (ORDER BY ts, start DESC) - ts AS dur, 98 start 99 FROM ( 100 SELECT 101 ts, 102 EXTRACT_ARG(arg_set_id, 'action') AS action, 103 EXTRACT_ARG(arg_set_id, 'start') AS start 104 FROM raw 105 WHERE name = 'suspend_resume' 106 ) 107 -- Different device kernels log different actions when suspending. 108 -- Fortunately each action only appears in the kernel in which it's 109 -- relevant so we can simply look for any of them. 110 WHERE action IN ('timekeeping_freeze', 'syscore_resume') 111) 112WHERE start = 1 113UNION ALL 114-- Traces from before b/70292203 was fixed (approx Nov 2020) do not have the 115-- action string so we do some convoluted pattern matching that mostly works. 116-- TODO(simonmacm) remove this when we no longer need suspend-resume from R 117-- phones. 118SELECT 119 ts, 120 dur, 121 false as trustworthy 122FROM ( 123 SELECT 124 ts, 125 ts - lag(ts) OVER w AS lag_dur, 126 lead(ts) OVER w - ts AS dur, 127 action, 128 start, 129 event, 130 lag(start) OVER w AS lag_start, 131 lag(event) OVER w AS lag_event, 132 lag(start, 2) OVER w AS lag_2_start, 133 lag(event, 2) OVER w AS lag_2_event, 134 lead(start) OVER w AS lead_start, 135 lead(event) OVER w AS lead_event, 136 lead(start, 2) OVER w AS lead_2_start, 137 lead(event, 2) OVER w AS lead_2_event 138 FROM ( 139 SELECT 140 ts, 141 EXTRACT_ARG(arg_set_id, 'action') AS action, 142 EXTRACT_ARG(arg_set_id, 'start') AS start, 143 EXTRACT_ARG(arg_set_id, 'val') AS event 144 FROM raw 145 WHERE name = 'suspend_resume' 146 ) 147 WINDOW w AS (ORDER BY ts) 148) 149WHERE action IS NULL AND ( 150-- We want to find the start and end events with action='timekeeping_freeze'. 151-- In practice, these events often show up in a sequence like the following: 152-- start = 1, event = 1 [string would have been 'machine_suspend'] 153-- start = 1, event = (any) [string would have been 'timekeeping_freeze'] * 154-- 155-- (sleep happens here) 156-- 157-- start = 0, event = (any) [string would have been 'timekeeping_freeze'] 158-- start = 0, event = 1 [string would have been 'machine_suspend'] 159-- 160-- So we look for this pattern of start and event, anchored on the event marked 161-- with "*". 162 ( 163 lag_start = 1 AND lag_event = 1 164 AND start = 1 165 AND lead_start = 0 166 AND lead_2_start = 0 AND lead_2_event = 1 167 ) 168-- Or in newer kernels we seem to have a very different pattern. We can take 169-- advantage of that fact that we get several events with identical timestamp 170-- just before sleeping (normally this never happens): 171-- gap = 0, start = 1, event = 3 172-- gap = 0, start = 0, event = 3 173-- gap = 0, start = 1, event = 0 174-- 175-- (sleep happens here) 176-- 177-- gap = (any), start = 0, event = 0 178 OR ( 179 lag_dur = 0 180 AND lead_start = 0 AND lead_event = 0 181 AND start = 1 AND event = 0 182 AND lag_start = 0 AND lag_event = 3 183 AND lag_2_start = 1 AND lag_2_event = 3 184 ) 185); 186 187SELECT RUN_METRIC('android/global_counter_span_view.sql', 188 'table_name', 'screen_state', 189 'counter_name', 'ScreenState'); 190 191DROP TABLE IF EXISTS screen_state_span_with_suspend; 192CREATE VIRTUAL TABLE screen_state_span_with_suspend 193 USING span_join(screen_state_span, suspend_slice_); 194 195DROP VIEW IF EXISTS android_batt_event; 196CREATE VIEW android_batt_event AS 197SELECT 198 ts, 199 dur, 200 'Suspended' AS slice_name, 201 'Suspend / resume' AS track_name, 202 'slice' AS track_type 203FROM suspend_slice_; 204 205DROP VIEW IF EXISTS android_batt_output; 206CREATE VIEW android_batt_output AS 207SELECT AndroidBatteryMetric( 208 'battery_counters', ( 209 SELECT RepeatedField( 210 AndroidBatteryMetric_BatteryCounters( 211 'timestamp_ns', ts, 212 'charge_counter_uah', charge_uah, 213 'capacity_percent', capacity_percent, 214 'current_ua', current_ua, 215 'current_avg_ua', current_avg_ua 216 ) 217 ) 218 FROM battery_view 219 ), 220 'battery_aggregates', ( 221 SELECT NULL_IF_EMPTY(AndroidBatteryMetric_BatteryAggregates( 222 'total_screen_off_ns', 223 SUM(CASE WHEN state = 1.0 AND tbl = 'total' THEN dur ELSE 0 END), 224 'total_screen_on_ns', 225 SUM(CASE WHEN state = 2.0 AND tbl = 'total' THEN dur ELSE 0 END), 226 'total_screen_doze_ns', 227 SUM(CASE WHEN state = 3.0 AND tbl = 'total' THEN dur ELSE 0 END), 228 'sleep_ns', 229 (SELECT SUM(dur) FROM suspend_slice_), 230 'sleep_screen_off_ns', 231 SUM(CASE WHEN state = 1.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 232 'sleep_screen_on_ns', 233 SUM(CASE WHEN state = 2.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 234 'sleep_screen_doze_ns', 235 SUM(CASE WHEN state = 3.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 236 'total_wakelock_ns', 237 (SELECT SUM(ts_end - ts) FROM android_batt_wakelocks_merged) 238 )) 239 FROM ( 240 SELECT dur, screen_state_val AS state, 'total' AS tbl 241 FROM screen_state_span 242 UNION ALL 243 SELECT dur, screen_state_val AS state, 'sleep' AS tbl 244 FROM screen_state_span_with_suspend 245 ) 246 ), 247 'suspend_period', ( 248 SELECT RepeatedField( 249 AndroidBatteryMetric_SuspendPeriod( 250 'timestamp_ns', ts, 251 'duration_ns', dur 252 ) 253 ) 254 FROM suspend_slice_ 255 WHERE trustworthy 256 ) 257); 258