xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.ThreadState/thread_state_track.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 {colorForState} from '../../components/colorizer';
16import {
17  BASE_ROW,
18  BaseSliceTrack,
19  OnSliceClickArgs,
20} from '../../components/tracks/base_slice_track';
21import {
22  SLICE_LAYOUT_FLAT_DEFAULTS,
23  SliceLayout,
24} from '../../components/tracks/slice_layout';
25import {LONG, NUM, NUM_NULL, STR} from '../../trace_processor/query_result';
26import {Slice} from '../../public/track';
27import {translateState} from '../../components/sql_utils/thread_state';
28import {TrackEventDetails, TrackEventSelection} from '../../public/selection';
29import {ThreadStateDetailsPanel} from './thread_state_details_panel';
30import {Trace} from '../../public/trace';
31import {Dataset, SourceDataset} from '../../trace_processor/dataset';
32
33export const THREAD_STATE_ROW = {
34  ...BASE_ROW,
35  state: STR,
36  ioWait: NUM_NULL,
37};
38
39export type ThreadStateRow = typeof THREAD_STATE_ROW;
40
41export class ThreadStateTrack extends BaseSliceTrack<Slice, ThreadStateRow> {
42  protected sliceLayout: SliceLayout = {...SLICE_LAYOUT_FLAT_DEFAULTS};
43
44  constructor(
45    trace: Trace,
46    uri: string,
47    private utid: number,
48  ) {
49    super(trace, uri);
50  }
51
52  // This is used by the base class to call iter().
53  getRowSpec(): ThreadStateRow {
54    return THREAD_STATE_ROW;
55  }
56
57  getSqlSource(): string {
58    // Do not display states: 'S' (sleeping), 'I' (idle kernel thread).
59    return `
60      select
61        id,
62        ts,
63        dur,
64        cpu,
65        state,
66        io_wait as ioWait,
67        0 as depth
68      from thread_state
69      where
70        utid = ${this.utid} and
71        state not in ('S', 'I')
72    `;
73  }
74
75  getDataset(): Dataset | undefined {
76    return new SourceDataset({
77      src: 'thread_state',
78      schema: {
79        id: NUM,
80        ts: LONG,
81        dur: LONG,
82        cpu: NUM,
83        state: STR,
84        io_wait: NUM_NULL,
85        utid: NUM,
86      },
87      filter: {
88        col: 'utid',
89        eq: this.utid,
90      },
91    });
92  }
93
94  rowToSlice(row: ThreadStateRow): Slice {
95    const baseSlice = this.rowToSliceBase(row);
96    const ioWait = row.ioWait === null ? undefined : !!row.ioWait;
97    const title = translateState(row.state, ioWait);
98    const color = colorForState(title);
99    return {...baseSlice, title, colorScheme: color};
100  }
101
102  onUpdatedSlices(slices: Slice[]) {
103    for (const slice of slices) {
104      slice.isHighlighted = slice === this.hoveredSlice;
105    }
106  }
107
108  onSliceClick(args: OnSliceClickArgs<Slice>) {
109    this.trace.selection.selectTrackEvent(this.uri, args.slice.id);
110  }
111
112  // Add utid to selection details
113  override async getSelectionDetails(
114    id: number,
115  ): Promise<TrackEventDetails | undefined> {
116    const details = await super.getSelectionDetails(id);
117    return details && {...details, utid: this.utid};
118  }
119
120  detailsPanel({eventId}: TrackEventSelection) {
121    return new ThreadStateDetailsPanel(this.trace, eventId);
122  }
123}
124