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