xref: /aosp_15_r20/development/tools/winscope/src/parsers/perfetto/utils.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker/*
2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker *
4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker *
8*90c8c64dSAndroid Build Coastguard Worker *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker *
10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker */
16*90c8c64dSAndroid Build Coastguard Worker
17*90c8c64dSAndroid Build Coastguard Workerimport {assertDefined, assertTrue} from 'common/assert_utils';
18*90c8c64dSAndroid Build Coastguard Workerimport {UserNotifier} from 'common/user_notifier';
19*90c8c64dSAndroid Build Coastguard Workerimport {MissingVsyncId} from 'messaging/user_warnings';
20*90c8c64dSAndroid Build Coastguard Workerimport {AbsoluteEntryIndex, EntriesRange} from 'trace/trace';
21*90c8c64dSAndroid Build Coastguard Workerimport {WasmEngineProxy} from 'trace_processor/wasm_engine_proxy';
22*90c8c64dSAndroid Build Coastguard Workerimport {FakeProto, FakeProtoBuilder} from './fake_proto_builder';
23*90c8c64dSAndroid Build Coastguard Worker
24*90c8c64dSAndroid Build Coastguard Workerexport class Utils {
25*90c8c64dSAndroid Build Coastguard Worker  static async queryEntry(
26*90c8c64dSAndroid Build Coastguard Worker    traceProcessor: WasmEngineProxy,
27*90c8c64dSAndroid Build Coastguard Worker    tableName: string,
28*90c8c64dSAndroid Build Coastguard Worker    entryIndexToRowIdMap: number[],
29*90c8c64dSAndroid Build Coastguard Worker    entryIndex: AbsoluteEntryIndex,
30*90c8c64dSAndroid Build Coastguard Worker  ): Promise<FakeProto> {
31*90c8c64dSAndroid Build Coastguard Worker    const rowId = entryIndexToRowIdMap[entryIndex];
32*90c8c64dSAndroid Build Coastguard Worker    const sql = `
33*90c8c64dSAndroid Build Coastguard Worker      SELECT
34*90c8c64dSAndroid Build Coastguard Worker          tbl.id,
35*90c8c64dSAndroid Build Coastguard Worker          args.key,
36*90c8c64dSAndroid Build Coastguard Worker          args.value_type,
37*90c8c64dSAndroid Build Coastguard Worker          args.int_value,
38*90c8c64dSAndroid Build Coastguard Worker          args.string_value,
39*90c8c64dSAndroid Build Coastguard Worker          args.real_value
40*90c8c64dSAndroid Build Coastguard Worker      FROM ${tableName} AS tbl
41*90c8c64dSAndroid Build Coastguard Worker      INNER JOIN args ON tbl.arg_set_id = args.arg_set_id
42*90c8c64dSAndroid Build Coastguard Worker      WHERE tbl.id = ${rowId};
43*90c8c64dSAndroid Build Coastguard Worker    `;
44*90c8c64dSAndroid Build Coastguard Worker    const result = await traceProcessor.query(sql).waitAllRows();
45*90c8c64dSAndroid Build Coastguard Worker
46*90c8c64dSAndroid Build Coastguard Worker    const builder = new FakeProtoBuilder();
47*90c8c64dSAndroid Build Coastguard Worker    for (const it = result.iter({}); it.valid(); it.next()) {
48*90c8c64dSAndroid Build Coastguard Worker      builder.addArg(
49*90c8c64dSAndroid Build Coastguard Worker        it.get('key') as string,
50*90c8c64dSAndroid Build Coastguard Worker        it.get('value_type') as string,
51*90c8c64dSAndroid Build Coastguard Worker        it.get('int_value') as bigint | undefined,
52*90c8c64dSAndroid Build Coastguard Worker        it.get('real_value') as number | undefined,
53*90c8c64dSAndroid Build Coastguard Worker        it.get('string_value') as string | undefined,
54*90c8c64dSAndroid Build Coastguard Worker      );
55*90c8c64dSAndroid Build Coastguard Worker    }
56*90c8c64dSAndroid Build Coastguard Worker    return builder.build();
57*90c8c64dSAndroid Build Coastguard Worker  }
58*90c8c64dSAndroid Build Coastguard Worker
59*90c8c64dSAndroid Build Coastguard Worker  static async queryVsyncId(
60*90c8c64dSAndroid Build Coastguard Worker    traceProcessor: WasmEngineProxy,
61*90c8c64dSAndroid Build Coastguard Worker    tableName: string,
62*90c8c64dSAndroid Build Coastguard Worker    entryIndexToRowIdMap: number[],
63*90c8c64dSAndroid Build Coastguard Worker    entriesRange: EntriesRange,
64*90c8c64dSAndroid Build Coastguard Worker    createVsyncIdQuery: (
65*90c8c64dSAndroid Build Coastguard Worker      tableName: string,
66*90c8c64dSAndroid Build Coastguard Worker      minRowId: number,
67*90c8c64dSAndroid Build Coastguard Worker      maxRowId: number,
68*90c8c64dSAndroid Build Coastguard Worker    ) => string = Utils.createDefaultVsyncIdQuery,
69*90c8c64dSAndroid Build Coastguard Worker  ): Promise<Array<bigint>> {
70*90c8c64dSAndroid Build Coastguard Worker    let minRowId = Number.MAX_VALUE;
71*90c8c64dSAndroid Build Coastguard Worker    let maxRowId = Number.MIN_VALUE;
72*90c8c64dSAndroid Build Coastguard Worker    for (
73*90c8c64dSAndroid Build Coastguard Worker      let entryIndex = entriesRange.start;
74*90c8c64dSAndroid Build Coastguard Worker      entryIndex < entriesRange.end;
75*90c8c64dSAndroid Build Coastguard Worker      ++entryIndex
76*90c8c64dSAndroid Build Coastguard Worker    ) {
77*90c8c64dSAndroid Build Coastguard Worker      const rowId = entryIndexToRowIdMap[entryIndex];
78*90c8c64dSAndroid Build Coastguard Worker      minRowId = Math.min(minRowId, rowId);
79*90c8c64dSAndroid Build Coastguard Worker      maxRowId = Math.max(maxRowId, rowId);
80*90c8c64dSAndroid Build Coastguard Worker    }
81*90c8c64dSAndroid Build Coastguard Worker    const numEntries = maxRowId - minRowId + 1;
82*90c8c64dSAndroid Build Coastguard Worker
83*90c8c64dSAndroid Build Coastguard Worker    const sql = createVsyncIdQuery(tableName, minRowId, maxRowId);
84*90c8c64dSAndroid Build Coastguard Worker    const result = await traceProcessor.query(sql).waitAllRows();
85*90c8c64dSAndroid Build Coastguard Worker
86*90c8c64dSAndroid Build Coastguard Worker    const vsyncIdOrderedByRow: Array<bigint> = [];
87*90c8c64dSAndroid Build Coastguard Worker    let curRowId = BigInt(minRowId);
88*90c8c64dSAndroid Build Coastguard Worker    for (const it = result.iter({}); it.valid(); it.next()) {
89*90c8c64dSAndroid Build Coastguard Worker      const id = assertDefined(it.get('id') as bigint | undefined);
90*90c8c64dSAndroid Build Coastguard Worker      while (curRowId < id) {
91*90c8c64dSAndroid Build Coastguard Worker        // Handle missing table rows that don't have a vsync_id
92*90c8c64dSAndroid Build Coastguard Worker        vsyncIdOrderedByRow.push(-1n);
93*90c8c64dSAndroid Build Coastguard Worker        curRowId++;
94*90c8c64dSAndroid Build Coastguard Worker      }
95*90c8c64dSAndroid Build Coastguard Worker      assertTrue(
96*90c8c64dSAndroid Build Coastguard Worker        curRowId === id,
97*90c8c64dSAndroid Build Coastguard Worker        () => 'query for vsyncId contains duplicate rows with the same id',
98*90c8c64dSAndroid Build Coastguard Worker      );
99*90c8c64dSAndroid Build Coastguard Worker      const value = it.get('int_value') as bigint | undefined;
100*90c8c64dSAndroid Build Coastguard Worker      const valueType = it.get('value_type') as string;
101*90c8c64dSAndroid Build Coastguard Worker      assertTrue(
102*90c8c64dSAndroid Build Coastguard Worker        valueType === 'uint' || valueType === 'int',
103*90c8c64dSAndroid Build Coastguard Worker        () => 'expected vsync_id to have integer type',
104*90c8c64dSAndroid Build Coastguard Worker      );
105*90c8c64dSAndroid Build Coastguard Worker      vsyncIdOrderedByRow.push(value ?? -1n);
106*90c8c64dSAndroid Build Coastguard Worker      curRowId++;
107*90c8c64dSAndroid Build Coastguard Worker    }
108*90c8c64dSAndroid Build Coastguard Worker    while (curRowId <= maxRowId) {
109*90c8c64dSAndroid Build Coastguard Worker      // Handle missing table rows at the end of the trace
110*90c8c64dSAndroid Build Coastguard Worker      vsyncIdOrderedByRow.push(-1n);
111*90c8c64dSAndroid Build Coastguard Worker      curRowId++;
112*90c8c64dSAndroid Build Coastguard Worker    }
113*90c8c64dSAndroid Build Coastguard Worker
114*90c8c64dSAndroid Build Coastguard Worker    if (vsyncIdOrderedByRow.length !== numEntries) {
115*90c8c64dSAndroid Build Coastguard Worker      UserNotifier.add(new MissingVsyncId(tableName));
116*90c8c64dSAndroid Build Coastguard Worker    }
117*90c8c64dSAndroid Build Coastguard Worker
118*90c8c64dSAndroid Build Coastguard Worker    const vsyncIdOrderedByEntry: Array<bigint> = [];
119*90c8c64dSAndroid Build Coastguard Worker    for (
120*90c8c64dSAndroid Build Coastguard Worker      let entryIndex = entriesRange.start;
121*90c8c64dSAndroid Build Coastguard Worker      entryIndex < entriesRange.end;
122*90c8c64dSAndroid Build Coastguard Worker      ++entryIndex
123*90c8c64dSAndroid Build Coastguard Worker    ) {
124*90c8c64dSAndroid Build Coastguard Worker      const rowId = entryIndexToRowIdMap[entryIndex];
125*90c8c64dSAndroid Build Coastguard Worker      const vsyncId = vsyncIdOrderedByRow[rowId - minRowId];
126*90c8c64dSAndroid Build Coastguard Worker      vsyncIdOrderedByEntry.push(vsyncId);
127*90c8c64dSAndroid Build Coastguard Worker    }
128*90c8c64dSAndroid Build Coastguard Worker
129*90c8c64dSAndroid Build Coastguard Worker    return vsyncIdOrderedByEntry;
130*90c8c64dSAndroid Build Coastguard Worker  }
131*90c8c64dSAndroid Build Coastguard Worker
132*90c8c64dSAndroid Build Coastguard Worker  // Creates a sql query for the vsync_id of the table rows that have
133*90c8c64dSAndroid Build Coastguard Worker  // an id in the range [minRowId, maxRowId]. The query may be created in a way
134*90c8c64dSAndroid Build Coastguard Worker  // where rows that don't have a vsync_id can be omitted from the query result.
135*90c8c64dSAndroid Build Coastguard Worker  private static createDefaultVsyncIdQuery(
136*90c8c64dSAndroid Build Coastguard Worker    tableName: string,
137*90c8c64dSAndroid Build Coastguard Worker    minRowId: number,
138*90c8c64dSAndroid Build Coastguard Worker    maxRowId: number,
139*90c8c64dSAndroid Build Coastguard Worker  ): string {
140*90c8c64dSAndroid Build Coastguard Worker    return `
141*90c8c64dSAndroid Build Coastguard Worker      SELECT
142*90c8c64dSAndroid Build Coastguard Worker        tbl.id AS id,
143*90c8c64dSAndroid Build Coastguard Worker        args.key,
144*90c8c64dSAndroid Build Coastguard Worker        args.value_type,
145*90c8c64dSAndroid Build Coastguard Worker        args.int_value
146*90c8c64dSAndroid Build Coastguard Worker      FROM ${tableName} AS tbl
147*90c8c64dSAndroid Build Coastguard Worker      INNER JOIN args ON tbl.arg_set_id = args.arg_set_id
148*90c8c64dSAndroid Build Coastguard Worker      WHERE
149*90c8c64dSAndroid Build Coastguard Worker        tbl.id BETWEEN ${minRowId} AND ${maxRowId}
150*90c8c64dSAndroid Build Coastguard Worker        AND args.key = 'vsync_id'
151*90c8c64dSAndroid Build Coastguard Worker        ORDER BY tbl.id;
152*90c8c64dSAndroid Build Coastguard Worker    `;
153*90c8c64dSAndroid Build Coastguard Worker  }
154*90c8c64dSAndroid Build Coastguard Worker}
155