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 intervals.intersect; 17 18-- The time a thread spent in each scheduling state during it's lifetime. 19CREATE PERFETTO TABLE sched_time_in_state_for_thread ( 20 -- Utid of the thread. 21 utid JOINID(thread.id), 22 -- Total runtime of thread. 23 total_runtime LONG, 24 -- One of the scheduling states of kernel thread. 25 state STRING, 26 -- Total time spent in the scheduling state. 27 time_in_state LONG, 28 -- Percentage of time thread spent in scheduling state in [0-100] range. 29 percentage_in_state LONG 30) AS 31WITH 32 total_dur AS ( 33 SELECT 34 utid, 35 sum(dur) AS sum_dur 36 FROM thread_state 37 GROUP BY 38 1 39 ), 40 summed AS ( 41 SELECT 42 utid, 43 state, 44 sum(dur) AS time_in_state 45 FROM thread_state 46 GROUP BY 47 1, 48 2 49 ) 50SELECT 51 utid, 52 sum_dur AS total_runtime, 53 state, 54 time_in_state, 55 ( 56 time_in_state * 100 57 ) / ( 58 sum_dur 59 ) AS percentage_in_state 60FROM summed 61JOIN total_dur 62 USING (utid); 63 64CREATE PERFETTO MACRO _case_for_state( 65 state Expr 66) 67RETURNS Expr AS 68max(CASE WHEN state = $state THEN percentage_in_state END); 69 70-- Summary of time spent by thread in each scheduling state, in percentage ([0, 100] 71-- ranges). Sum of all states might be smaller than 100, as those values 72-- are rounded down. 73CREATE PERFETTO TABLE sched_percentage_of_time_in_state ( 74 -- Utid of the thread. 75 utid JOINID(thread.id), 76 -- Percentage of time thread spent in running ('Running') state in [0, 100] 77 -- range. 78 running LONG, 79 -- Percentage of time thread spent in runnable ('R') state in [0, 100] 80 -- range. 81 runnable LONG, 82 -- Percentage of time thread spent in preempted runnable ('R+') state in 83 -- [0, 100] range. 84 runnable_preempted LONG, 85 -- Percentage of time thread spent in sleeping ('S') state in [0, 100] range. 86 sleeping LONG, 87 -- Percentage of time thread spent in uninterruptible sleep ('D') state in 88 -- [0, 100] range. 89 uninterruptible_sleep LONG, 90 -- Percentage of time thread spent in other ('T', 't', 'X', 'Z', 'x', 'I', 91 -- 'K', 'W', 'P', 'N') states in [0, 100] range. 92 other LONG 93) AS 94SELECT 95 utid, 96 _case_for_state!('Running') AS running, 97 _case_for_state!('R') AS runnable, 98 _case_for_state!('R+') AS runnable_preempted, 99 _case_for_state!('S') AS sleeping, 100 _case_for_state!('D') AS uninterruptible_sleep, 101 sum( 102 CASE 103 WHEN state IN ('T', 't', 'X', 'Z', 'x', 'I', 'K', 'W', 'P', 'N') 104 THEN time_in_state 105 END 106 ) * 100 / total_runtime AS other 107FROM sched_time_in_state_for_thread 108GROUP BY 109 utid; 110 111-- Time the thread spent each state in a given interval. 112-- 113-- This function is only designed to run over a small number of intervals 114-- (10-100 at most). It will be *very slow* for large sets of intervals. 115-- 116-- Specifically for any non-trivial subset of thread slices, prefer using 117-- `thread_slice_time_in_state` in the `slices.time_in_state` module for this 118-- purpose instead. 119CREATE PERFETTO FUNCTION sched_time_in_state_for_thread_in_interval( 120 -- The start of the interval. 121 ts TIMESTAMP, 122 -- The duration of the interval. 123 dur DURATION, 124 -- The utid of the thread. 125 utid JOINID(thread.id) 126) 127RETURNS TABLE ( 128 -- The scheduling state (from the `thread_state` table). 129 -- 130 -- Use the `sched_state_to_human_readable_string` function in the `sched` 131 -- package to get full name. 132 state STRING, 133 -- A (posssibly NULL) boolean indicating, if the device was in uninterruptible 134 -- sleep, if it was an IO sleep. 135 io_wait BOOL, 136 -- If the `state` is uninterruptible sleep, `io_wait` indicates if it was 137 -- an IO sleep. Will be null if `state` is *not* uninterruptible sleep or if 138 -- we cannot tell if it was an IO sleep or not. 139 -- 140 -- Only available on Android when 141 -- `sched/sched_blocked_reason` ftrace tracepoint is enabled. 142 blocked_function LONG, 143 -- The duration of time the threads slice spent for each 144 -- (state, io_wait, blocked_function) tuple. 145 dur DURATION 146) AS 147SELECT 148 state, 149 io_wait, 150 blocked_function, 151 sum(ii.dur) AS dur 152FROM thread_state 153JOIN ( 154 SELECT 155 * 156 FROM _interval_intersect_single!( 157 $ts, $dur, 158 ( 159 SELECT id, ts, dur 160 FROM thread_state 161 WHERE utid = $utid AND dur > 0 162 ) 163 ) 164) AS ii 165 USING (id) 166GROUP BY 167 1, 168 2, 169 3 170ORDER BY 171 4 DESC; 172 173-- Time the thread spent each state and cpu in a given interval. 174CREATE PERFETTO FUNCTION sched_time_in_state_and_cpu_for_thread_in_interval( 175 -- The start of the interval. 176 ts TIMESTAMP, 177 -- The duration of the interval. 178 dur DURATION, 179 -- The utid of the thread. 180 utid JOINID(thread.id) 181) 182RETURNS TABLE ( 183 -- Thread state (from the `thread_state` table). 184 -- Use `sched_state_to_human_readable_string` function to get full name. 185 state STRING, 186 -- A (posssibly NULL) boolean indicating, if the device was in uninterruptible 187 -- sleep, if it was an IO sleep. 188 io_wait BOOL, 189 -- Id of the CPU. 190 cpu LONG, 191 -- Some states can specify the blocked function. Usually NULL. 192 blocked_function LONG, 193 -- Total time spent with this state, cpu and blocked function. 194 dur DURATION 195) AS 196SELECT 197 state, 198 io_wait, 199 cpu, 200 blocked_function, 201 sum(ii.dur) AS dur 202FROM thread_state 203JOIN ( 204 SELECT 205 * 206 FROM _interval_intersect_single!( 207 $ts, $dur, 208 (SELECT id, ts, dur 209 FROM thread_state 210 WHERE utid = $utid AND dur > 0)) 211) AS ii 212 USING (id) 213GROUP BY 214 1, 215 2, 216 3, 217 4 218ORDER BY 219 5 DESC; 220 221-- Time spent by CPU in each scheduling state in a provided interval. 222CREATE PERFETTO FUNCTION sched_time_in_state_for_cpu_in_interval( 223 -- CPU id. 224 cpu LONG, 225 -- Interval start. 226 ts TIMESTAMP, 227 -- Interval duration. 228 dur LONG 229) 230RETURNS TABLE ( 231 -- End state. From `sched.end_state`. 232 end_state STRING, 233 -- Duration in state. 234 dur LONG 235) AS 236WITH 237 sched_for_cpu AS ( 238 SELECT 239 id, 240 ts, 241 dur 242 FROM sched 243 WHERE 244 cpu = $cpu AND dur != -1 245 ) 246SELECT 247 end_state, 248 sum(ii.dur) AS dur 249FROM sched 250JOIN _interval_intersect_single!($ts, $dur, sched_for_cpu) AS ii 251 USING (id) 252GROUP BY 253 end_state; 254