• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2023 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';
16
17import {ColumnType} from '../../common/query_result';
18import {tpDurationFromSql, tpTimeFromSql} from '../../common/time';
19import {
20  BottomTab,
21  bottomTabRegistry,
22  NewBottomTabArgs,
23} from '../../frontend/bottom_tab';
24import {globals} from '../../frontend/globals';
25import {asTPTimestamp} from '../../frontend/sql_types';
26import {Duration} from '../../frontend/widgets/duration';
27import {Timestamp} from '../../frontend/widgets/timestamp';
28import {dictToTree} from '../../frontend/widgets/tree';
29
30import {ARG_PREFIX} from './add_debug_track_menu';
31
32interface DebugSliceDetailsTabConfig {
33  sqlTableName: string;
34  id: number;
35}
36
37function SqlValueToString(val: ColumnType) {
38  if (val instanceof Uint8Array) {
39    return `<blob length=${val.length}>`;
40  }
41  if (val === null) {
42    return 'NULL';
43  }
44  return val.toString();
45}
46
47export class DebugSliceDetailsTab extends
48    BottomTab<DebugSliceDetailsTabConfig> {
49  static readonly kind = 'org.perfetto.DebugSliceDetailsTab';
50
51  data: {[key: string]: ColumnType}|undefined;
52
53  static create(args: NewBottomTabArgs): DebugSliceDetailsTab {
54    return new DebugSliceDetailsTab(args);
55  }
56
57  constructor(args: NewBottomTabArgs) {
58    super(args);
59
60    this.engine
61        .query(`select * from ${this.config.sqlTableName} where id = ${
62            this.config.id}`)
63        .then((queryResult) => {
64          this.data = queryResult.firstRow({});
65          globals.rafScheduler.scheduleFullRedraw();
66        });
67  }
68
69  viewTab() {
70    if (this.data === undefined) {
71      return m('h2', 'Loading');
72    }
73    const left = dictToTree({
74      'Name': this.data['name'] as string,
75      'Start time':
76          m(Timestamp, {ts: asTPTimestamp(tpTimeFromSql(this.data['ts']))}),
77      'Duration': m(Duration, {dur: tpDurationFromSql(this.data['dur'])}),
78      'Debug slice id': `${this.config.sqlTableName}[${this.config.id}]`,
79    });
80    const args: {[key: string]: m.Child} = {};
81    for (const key of Object.keys(this.data)) {
82      if (key.startsWith(ARG_PREFIX)) {
83        args[key.substr(ARG_PREFIX.length)] = SqlValueToString(this.data[key]);
84      }
85    }
86    return m(
87        '.details-panel',
88        m('header.overview', m('span', 'Debug Slice')),
89        m('.details-table-multicolumn',
90          {
91            style: {
92              'user-select': 'text',
93            },
94          },
95          m('.half-width-panel', left),
96          m('.half-width-panel', dictToTree(args))));
97  }
98
99  getTitle(): string {
100    return `Current Selection`;
101  }
102
103  isLoading() {
104    return this.data === undefined;
105  }
106
107  renderTabCanvas() {
108    return;
109  }
110}
111
112bottomTabRegistry.register(DebugSliceDetailsTab);
113