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-- 16INCLUDE PERFETTO MODULE android.battery; 17INCLUDE PERFETTO MODULE android.battery_stats; 18INCLUDE PERFETTO MODULE android.suspend; 19INCLUDE PERFETTO MODULE counters.intervals; 20 21DROP VIEW IF EXISTS battery_view; 22CREATE PERFETTO VIEW battery_view AS 23SELECT * FROM android_battery_charge; 24 25DROP TABLE IF EXISTS android_batt_wakelocks_merged; 26CREATE PERFETTO TABLE android_batt_wakelocks_merged AS 27SELECT 28 MIN(ts) AS ts, 29 MAX(ts_end) AS ts_end 30FROM ( 31 SELECT 32 *, 33 SUM(new_group) OVER (ORDER BY ts) AS group_id 34 FROM ( 35 SELECT 36 ts, 37 ts + dur AS ts_end, 38 -- There is a new group if there was a gap before this wakelock. 39 -- i.e. the max end timestamp of all preceding wakelocks is before 40 -- the start timestamp of this one. 41 -- The null check is for the first row which is always a new group. 42 IFNULL( 43 MAX(ts + dur) OVER ( 44 ORDER BY ts 45 ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 46 ) < ts, 47 TRUE 48 ) AS new_group 49 FROM slice 50 WHERE slice.name GLOB 'WakeLock *' AND dur != -1 51 ) 52) 53GROUP BY group_id; 54 55-- TODO(simonmacm) remove this shim once no longer used internally 56DROP TABLE IF EXISTS suspend_slice_; 57CREATE PERFETTO TABLE suspend_slice_ AS 58SELECT ts, dur FROM android_suspend_state where power_state = 'suspended'; 59 60DROP TABLE IF EXISTS screen_state_span; 61CREATE PERFETTO TABLE screen_state_span AS 62WITH screen_state AS ( 63 SELECT counter.id, ts, 0 AS track_id, value 64 FROM counter 65 JOIN counter_track ON counter_track.id = counter.track_id 66 WHERE name = 'ScreenState' 67) 68SELECT * FROM counter_leading_intervals!(screen_state); 69 70DROP TABLE IF EXISTS screen_state_span_with_suspend; 71CREATE VIRTUAL TABLE screen_state_span_with_suspend 72USING span_join(screen_state_span, suspend_slice_); 73 74DROP TABLE IF EXISTS power_mw_intervals; 75CREATE PERFETTO TABLE power_mw_intervals AS 76WITH power_mw_counter AS ( 77 SELECT counter.id, ts, track_id, value 78 FROM counter 79 JOIN counter_track ON counter_track.id = counter.track_id 80 WHERE name = 'batt.power_mw' 81) 82SELECT * FROM counter_leading_intervals!(power_mw_counter); 83 84DROP TABLE IF EXISTS charge_diff_mw; 85CREATE PERFETTO TABLE charge_diff_mw AS 86with energy_counters as ( 87select 88 ts, 89 CASE 90 WHEN energy_counter_uwh IS NOT NULL THEN energy_counter_uwh 91 ELSE charge_uah * voltage_uv / 1e12 END as energy 92 from android_battery_charge 93), start_energy as ( 94 select 95 min(ts) as ts, 96 energy 97 from energy_counters 98), end_energy as ( 99 select 100 max(ts) as ts, 101 energy 102 from energy_counters 103) 104select 105 -- If the battery is discharging, the start energy value will be greater than 106 -- the end and the estimate will report a positive value. 107 -- Battery energy is in watt hours, so multiply by 3600 to convert to joules. 108 -- Convert perfetto timestamp from nanoseconds to seconds. 109 -- Divide energy by seconds and convert to milliwatts. 110 (s.energy - e.energy) * 3600 * 1e3 / ((e.ts - s.ts) / 1e9) as estimate 111from start_energy s, end_energy e; 112 113DROP VIEW IF EXISTS android_batt_output; 114CREATE PERFETTO VIEW android_batt_output AS 115SELECT AndroidBatteryMetric( 116 'battery_counters', ( 117 SELECT RepeatedField( 118 AndroidBatteryMetric_BatteryCounters( 119 'timestamp_ns', ts, 120 'charge_counter_uah', charge_uah, 121 'capacity_percent', capacity_percent, 122 'current_ua', current_ua, 123 'current_avg_ua', current_avg_ua, 124 'voltage_uv', voltage_uv 125 ) 126 ) 127 FROM android_battery_charge 128 ), 129 'battery_aggregates', ( 130 SELECT NULL_IF_EMPTY(AndroidBatteryMetric_BatteryAggregates( 131 'total_screen_off_ns', 132 SUM(CASE WHEN state = 1.0 AND tbl = 'total' THEN dur ELSE 0 END), 133 'total_screen_on_ns', 134 SUM(CASE WHEN state = 2.0 AND tbl = 'total' THEN dur ELSE 0 END), 135 'total_screen_doze_ns', 136 SUM(CASE WHEN state = 3.0 AND tbl = 'total' THEN dur ELSE 0 END), 137 'sleep_ns', 138 (SELECT SUM(dur) FROM suspend_slice_), 139 'sleep_screen_off_ns', 140 SUM(CASE WHEN state = 1.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 141 'sleep_screen_on_ns', 142 SUM(CASE WHEN state = 2.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 143 'sleep_screen_doze_ns', 144 SUM(CASE WHEN state = 3.0 AND tbl = 'sleep' THEN dur ELSE 0 END), 145 'total_wakelock_ns', 146 (SELECT SUM(ts_end - ts) FROM android_batt_wakelocks_merged), 147 'avg_power_mw', 148 (SELECT SUM(value * dur) / SUM(dur) FROM power_mw_intervals), 149 'avg_power_from_charge_diff_mw', 150 (select estimate FROM charge_diff_mw) 151 )) 152 FROM ( 153 SELECT dur, value AS state, 'total' AS tbl 154 FROM screen_state_span 155 UNION ALL 156 SELECT dur, value AS state, 'sleep' AS tbl 157 FROM screen_state_span_with_suspend 158 ) 159 ), 160 'suspend_period', ( 161 SELECT RepeatedField( 162 AndroidBatteryMetric_SuspendPeriod( 163 'timestamp_ns', ts, 164 'duration_ns', dur 165 ) 166 ) 167 FROM suspend_slice_ 168 ) 169); 170