1-- 2-- Copyright 2024 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 counters.intervals; 17 18INCLUDE PERFETTO MODULE wattson.device_infos; 19 20-- Get the corresponding deep idle time offset based on device and CPU. 21CREATE PERFETTO VIEW _filtered_deep_idle_offsets AS 22SELECT 23 cpu, 24 offset_ns 25FROM _device_cpu_deep_idle_offsets AS offsets 26JOIN _wattson_device AS device 27 ON offsets.device = device.name; 28 29-- Adjust duration of active portion to be slightly longer to account for 30-- overhead cost of transitioning out of deep idle. This is done because the 31-- device is active and consumes power for longer than the logs actually report. 32CREATE PERFETTO TABLE _adjusted_deep_idle AS 33WITH 34 idle_prev AS ( 35 SELECT 36 ts, 37 lag(ts, 1, trace_start()) OVER (PARTITION BY cpu ORDER BY ts) AS prev_ts, 38 value AS idle, 39 cli.value - cli.delta_value AS idle_prev, 40 cct.cpu 41 -- Same as cpu_idle_counters, but extracts some additional info that isn't 42 -- nominally present in cpu_idle_counters, such that the already calculated 43 -- lag values are reused instead of recomputed 44 FROM counter_leading_intervals!(( 45 SELECT c.* 46 FROM counter c 47 JOIN cpu_counter_track cct ON cct.id = c.track_id AND cct.name = 'cpuidle' 48 )) AS cli 49 JOIN cpu_counter_track AS cct 50 ON cli.track_id = cct.id 51 ), 52 -- Adjusted ts if applicable, which makes the current active state longer if 53 -- it is coming from an idle exit. 54 idle_mod AS ( 55 SELECT 56 iif( 57 idle_prev = 1 AND idle = 4294967295, 58 -- extend ts backwards by offset_ns at most up to prev_ts 59 max(ts - offset_ns, prev_ts), 60 ts 61 ) AS ts, 62 cpu, 63 idle 64 FROM idle_prev 65 JOIN _filtered_deep_idle_offsets 66 USING (cpu) 67 ), 68 -- Use EITHER idle states as is OR device specific override of idle states 69 _cpu_idle AS ( 70 -- Idle state calculations as is 71 SELECT 72 ts, 73 lead(ts, 1, trace_end()) OVER (PARTITION BY cpu ORDER BY ts) - ts AS dur, 74 cpu, 75 cast_int!(IIF(idle = 4294967295, -1, idle)) AS idle 76 FROM idle_mod 77 WHERE 78 NOT EXISTS( 79 SELECT 80 1 81 FROM _idle_state_map_override 82 ) 83 UNION ALL 84 -- Device specific override of idle states 85 SELECT 86 ts, 87 lead(ts, 1, trace_end()) OVER (PARTITION BY cpu ORDER BY ts) - ts AS dur, 88 cpu, 89 override_idle AS idle 90 FROM idle_mod 91 JOIN _idle_state_map_override AS idle_map 92 ON idle_mod.idle = idle_map.nominal_idle 93 WHERE 94 EXISTS( 95 SELECT 96 1 97 FROM _idle_state_map_override 98 ) 99 ), 100 -- Get first idle transition per CPU 101 first_cpu_idle_slices AS ( 102 SELECT 103 ts, 104 cpu 105 FROM _cpu_idle 106 GROUP BY 107 cpu 108 ORDER BY 109 ts ASC 110 ) 111-- Prepend NULL slices up to first idle events on a per CPU basis 112SELECT 113 -- Construct slices from first cpu ts up to first freq event for each cpu 114 trace_start() AS ts, 115 first_slices.ts - trace_start() AS dur, 116 first_slices.cpu, 117 NULL AS idle 118FROM first_cpu_idle_slices AS first_slices 119WHERE 120 dur > 0 121UNION ALL 122SELECT 123 ts, 124 dur, 125 cpu, 126 idle 127FROM _cpu_idle 128-- Some durations are 0 post-adjustment and won't work with interval intersect 129WHERE 130 dur > 0 131UNION ALL 132-- Add empty cpu idle counters for CPUs that are physically present, but did not 133-- have a single idle event register. The time region needs to be defined so 134-- that interval_intersect doesn't remove the undefined time region. 135SELECT 136 trace_start() AS ts, 137 trace_dur() AS dur, 138 cpu, 139 NULL AS idle 140FROM _dev_cpu_policy_map 141WHERE 142 NOT cpu IN ( 143 SELECT 144 cpu 145 FROM first_cpu_idle_slices 146 ); 147