• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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