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 this 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 m from 'mithril'; 16import {Anchor} from '../../widgets/anchor'; 17import {Icons} from '../../base/semantic_icons'; 18import {Trace} from '../../public/trace'; 19import {QueryResult, Row} from '../../trace_processor/query_result'; 20import {SqlRef} from '../../widgets/sql_ref'; 21import {SqlTableDescription} from '../../components/widgets/sql/table/table_description'; 22import {MenuItem} from '../../widgets/menu'; 23import {extensions} from '../../components/extensions'; 24 25export const SCROLLS_TRACK_URI = 'perfetto.ChromeScrollJank#toplevelScrolls'; 26export const EVENT_LATENCY_TRACK_URI = 'perfetto.ChromeScrollJank#eventLatency'; 27export const JANKS_TRACK_URI = 'perfetto.ChromeScrollJank#scrollJankV3'; 28 29export function renderSliceRef(args: { 30 trace: Trace; 31 id: number; 32 trackUri: string; 33 title: m.Children; 34}) { 35 return m( 36 Anchor, 37 { 38 icon: Icons.UpdateSelection, 39 onclick: () => { 40 args.trace.selection.selectTrackEvent(args.trackUri, args.id, { 41 scrollToSelection: true, 42 }); 43 }, 44 }, 45 args.title, 46 ); 47} 48 49export function renderSqlRef(args: { 50 trace: Trace; 51 tableName: string; 52 tableDescription: SqlTableDescription | undefined; 53 id: number | bigint; 54}) { 55 return m(SqlRef, { 56 table: args.tableName, 57 id: args.id, 58 additionalMenuItems: args.tableDescription && [ 59 m(MenuItem, { 60 label: 'Show query results', 61 icon: 'table', 62 onclick: () => 63 extensions.addLegacySqlTableTab(args.trace, { 64 table: args.tableDescription!, 65 filters: [ 66 { 67 op: ([columnName]) => `${columnName} = ${args.id}`, 68 columns: ['id'], 69 }, 70 ], 71 }), 72 }), 73 ], 74 }); 75} 76 77/** 78 * Returns an array of the rows in `queryResult`. 79 * 80 * Warning: Only use this function in contexts where the number of rows is 81 * guaranteed to be small. Prefer doing transformations in SQL where possible. 82 */ 83export function rows<R extends Row>(queryResult: QueryResult, spec: R): R[] { 84 const results: R[] = []; 85 for (const it = queryResult.iter(spec); it.valid(); it.next()) { 86 const row: Row = {}; 87 for (const key of Object.keys(spec)) { 88 row[key] = it[key]; 89 } 90 results.push(row as R); 91 } 92 return results; 93} 94 95/** 96 * Converts a number to a boolean according to SQLite's conversion rules. 97 * 98 * See https://www.sqlite.org/lang_expr.html#boolean_expressions. 99 */ 100export function fromSqlBool(value: number): boolean; 101export function fromSqlBool(value: null): undefined; 102export function fromSqlBool(value: number | null): boolean | undefined; 103export function fromSqlBool(value: number | null): boolean | undefined { 104 if (value === null) { 105 return undefined; 106 } else { 107 return value !== 0; 108 } 109} 110