1// Copyright (C) 2024 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use size file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {assertTrue} from '../../base/logging'; 16import {duration, Time, time} from '../../base/time'; 17import {Engine} from '../../trace_processor/engine'; 18import { 19 LONG, 20 NUM, 21 NUM_NULL, 22 STR_NULL, 23} from '../../trace_processor/query_result'; 24import { 25 constraintsToQuerySuffix, 26 SQLConstraints, 27} from '../../trace_processor/sql_utils'; 28import { 29 asSchedSqlId, 30 asThreadStateSqlId, 31 asUtid, 32 SchedSqlId, 33 ThreadStateSqlId, 34 Utid, 35} from './core_types'; 36import {getThreadInfo, ThreadInfo} from './thread'; 37import {getThreadState, getThreadStateFromConstraints} from './thread_state'; 38 39// Representation of a single thread state object, corresponding to 40// a row for the |thread_slice| table. 41export interface Sched { 42 // Id into |sched| table. 43 id: SchedSqlId; 44 // Id of the corresponding entry in the |sched| table. 45 threadStateId?: ThreadStateSqlId; 46 // Timestamp of the beginning of this thread state in nanoseconds. 47 ts: time; 48 // Duration of this thread state in nanoseconds. 49 dur: duration; 50 cpu: number; 51 priority: number; 52 endState?: string; 53 thread: ThreadInfo; 54} 55 56export interface SchedWakeupInfo { 57 wakeupTs?: time; 58 wakerUtid?: Utid; 59 wakerCpu?: number; 60} 61 62// Gets a list of sched objects from Trace Processor with given 63// constraints. 64export async function getSchedFromConstraints( 65 engine: Engine, 66 constraints: SQLConstraints, 67): Promise<Sched[]> { 68 const query = await engine.query(` 69 SELECT 70 sched.id as schedSqlId, 71 ( 72 SELECT id 73 FROM thread_state 74 WHERE 75 thread_state.ts = sched.ts 76 AND thread_state.utid = sched.utid 77 ) as threadStateSqlId, 78 sched.ts, 79 sched.dur, 80 sched.cpu, 81 sched.priority as priority, 82 sched.end_state as endState, 83 sched.utid 84 FROM sched 85 ${constraintsToQuerySuffix(constraints)}`); 86 const it = query.iter({ 87 schedSqlId: NUM, 88 threadStateSqlId: NUM_NULL, 89 ts: LONG, 90 dur: LONG, 91 cpu: NUM, 92 priority: NUM, 93 endState: STR_NULL, 94 utid: NUM, 95 }); 96 97 const result: Sched[] = []; 98 99 for (; it.valid(); it.next()) { 100 result.push({ 101 id: asSchedSqlId(it.schedSqlId), 102 threadStateId: asThreadStateSqlId(it.threadStateSqlId ?? undefined), 103 ts: Time.fromRaw(it.ts), 104 dur: it.dur, 105 priority: it.priority, 106 endState: it.endState ?? undefined, 107 cpu: it.cpu ?? undefined, 108 thread: await getThreadInfo(engine, asUtid(it.utid)), 109 }); 110 } 111 return result; 112} 113 114export async function getSched( 115 engine: Engine, 116 id: SchedSqlId, 117): Promise<Sched | undefined> { 118 const result = await getSchedFromConstraints(engine, { 119 filters: [`sched.id=${id}`], 120 }); 121 assertTrue(result.length <= 1); 122 if (result.length === 0) { 123 return undefined; 124 } 125 return result[0]; 126} 127 128// Returns the thread and time of the wakeup that resulted in this running 129// sched slice. Omits wakeups that are known to be from interrupt context, 130// since we cannot always recover the correct waker cpu with the current 131// table layout. 132export async function getSchedWakeupInfo( 133 engine: Engine, 134 sched: Sched, 135): Promise<SchedWakeupInfo | undefined> { 136 const prevRunnable = await getThreadStateFromConstraints(engine, { 137 filters: [ 138 'state = "R"', 139 `ts + dur = ${sched.ts}`, 140 `utid = ${sched.thread.utid}`, 141 `(irq_context is null or irq_context = 0)`, 142 ], 143 }); 144 if (prevRunnable.length === 0 || prevRunnable[0].wakerId === undefined) { 145 return undefined; 146 } 147 const waker = await getThreadState(engine, prevRunnable[0].wakerId); 148 if (waker === undefined) { 149 return undefined; 150 } 151 return { 152 wakerCpu: waker?.cpu, 153 wakerUtid: prevRunnable[0].wakerUtid, 154 wakeupTs: prevRunnable[0].ts, 155 }; 156} 157