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 {BigintMath as BIMath} from '../../base/bigint_math'; 16import {clamp} from '../../base/math_utils'; 17import {NAMED_ROW, NamedSliceTrack} from './named_slice_track'; 18import {SLICE_LAYOUT_FIT_CONTENT_DEFAULTS} from './slice_layout'; 19import {LONG_NULL} from '../../trace_processor/query_result'; 20import {Slice} from '../../public/track'; 21import {TrackEventDetails} from '../../public/selection'; 22import {ThreadSliceDetailsPanel} from '../details/thread_slice_details_tab'; 23import {TraceImpl} from '../../core/trace_impl'; 24import {assertIsInstance} from '../../base/logging'; 25import {Trace} from '../../public/trace'; 26 27export const THREAD_SLICE_ROW = { 28 // Base columns (tsq, ts, dur, id, depth). 29 ...NAMED_ROW, 30 31 // Thread-specific columns. 32 threadDur: LONG_NULL, 33}; 34export type ThreadSliceRow = typeof THREAD_SLICE_ROW; 35 36export class ThreadSliceTrack extends NamedSliceTrack<Slice, ThreadSliceRow> { 37 constructor( 38 trace: Trace, 39 uri: string, 40 private readonly trackId: number, 41 maxDepth: number, 42 private readonly tableName: string = 'slice', 43 ) { 44 super(trace, uri); 45 this.sliceLayout = { 46 ...SLICE_LAYOUT_FIT_CONTENT_DEFAULTS, 47 depthGuess: maxDepth, 48 }; 49 } 50 51 // This is used by the base class to call iter(). 52 protected getRowSpec() { 53 return THREAD_SLICE_ROW; 54 } 55 56 getSqlSource(): string { 57 return ` 58 select 59 ts, 60 dur, 61 id, 62 depth, 63 ifnull(name, '') as name, 64 thread_dur as threadDur 65 from ${this.tableName} 66 where track_id = ${this.trackId} 67 `; 68 } 69 70 // Converts a SQL result row to an "Impl" Slice. 71 rowToSlice(row: ThreadSliceRow): Slice { 72 const namedSlice = this.rowToSliceBase(row); 73 74 if (row.dur > 0n && row.threadDur !== null) { 75 const fillRatio = clamp(BIMath.ratio(row.threadDur, row.dur), 0, 1); 76 return {...namedSlice, fillRatio}; 77 } else { 78 return namedSlice; 79 } 80 } 81 82 onUpdatedSlices(slices: Slice[]) { 83 for (const slice of slices) { 84 slice.isHighlighted = slice === this.hoveredSlice; 85 } 86 } 87 88 async getSelectionDetails( 89 id: number, 90 ): Promise<TrackEventDetails | undefined> { 91 const baseDetails = await super.getSelectionDetails(id); 92 if (!baseDetails) return undefined; 93 return { 94 ...baseDetails, 95 tableName: this.tableName, 96 }; 97 } 98 99 override detailsPanel() { 100 // Rationale for the assertIsInstance: ThreadSliceDetailsPanel requires a 101 // TraceImpl (because of flows) but here we must take a Trace interface, 102 // because this class is exposed to plugins (which see only Trace). 103 return new ThreadSliceDetailsPanel(assertIsInstance(this.trace, TraceImpl)); 104 } 105} 106