xref: /aosp_15_r20/external/perfetto/ui/src/components/sql_utils/sched.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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