• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2025 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 {assertExists} from '../../base/logging';
17import {Icons} from '../../base/semantic_icons';
18import {PivotTable} from '../../components/widgets/sql/pivot_table/pivot_table';
19import {PivotTableState} from '../../components/widgets/sql/pivot_table/pivot_table_state';
20import {getSqlTableDescription} from '../../components/widgets/sql/table/sql_table_registry';
21import {
22  AreaSelection,
23  areaSelectionsEqual,
24  AreaSelectionTab,
25} from '../../public/selection';
26import {SLICE_TRACK_KIND} from '../../public/track_kinds';
27import {Button} from '../../widgets/button';
28import {Trace} from '../../public/trace';
29import {extensions} from '../../components/extensions';
30
31export class PivotTableTab implements AreaSelectionTab {
32  readonly id = 'pivot_table';
33  readonly name = 'Pivot Table';
34
35  private state?: PivotTableState;
36  private previousSelection?: AreaSelection;
37  private trackIds: number[] = [];
38
39  constructor(private readonly trace: Trace) {}
40
41  render(selection: AreaSelection) {
42    if (
43      this.previousSelection === undefined ||
44      !areaSelectionsEqual(this.previousSelection, selection)
45    ) {
46      this.previousSelection = selection;
47      this.trackIds = selection.tracks
48        .filter((track) => track.tags?.kind == SLICE_TRACK_KIND)
49        .flatMap((track) => track.tags?.trackIds ?? []);
50      this.getOrCreateState().filters.setFilters([
51        {
52          op: (cols) => `${cols[0]} + ${cols[1]} > ${selection.start}`,
53          columns: ['ts', 'dur'],
54        },
55        {op: (cols) => `${cols[0]} < ${selection.end}`, columns: ['ts']},
56        {
57          op: (cols) => `${cols[0]} in (${this.trackIds.join(', ')})`,
58          columns: ['track_id'],
59        },
60      ]);
61    }
62    if (this.trackIds.length === 0) return undefined;
63    const state = this.getOrCreateState();
64
65    return {
66      isLoading: state?.getData() === undefined,
67      content: m(PivotTable, {
68        state,
69        extraRowButton: (node) =>
70          m(Button, {
71            icon: Icons.GoTo,
72            onclick: () => {
73              extensions.addLegacySqlTableTab(this.trace, {
74                table: assertExists(getSqlTableDescription('slice')),
75                filters: [
76                  ...(state?.filters.get() ?? []),
77                  ...node.getFilters(),
78                ],
79              });
80            },
81          }),
82      }),
83    };
84  }
85
86  private getOrCreateState(): PivotTableState {
87    if (this.state !== undefined) return this.state;
88    const sliceTable = assertExists(getSqlTableDescription('slice'));
89    const name = assertExists(
90      sliceTable.columns.find((c) => c.column === 'name'),
91    );
92    const dur = assertExists(
93      sliceTable.columns.find((c) => c.column === 'dur'),
94    );
95    this.state = new PivotTableState({
96      trace: this.trace,
97      table: sliceTable,
98      pivots: [name],
99      aggregations: [
100        {
101          column: dur,
102          op: 'sum',
103        },
104      ],
105    });
106    return this.state;
107  }
108}
109