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 {BigintMath as BIMath} from '../../base/bigint_math'; 16import {clamp} from '../../base/math_utils'; 17import {ThreadSliceDetailsPanel} from '../../components/details/thread_slice_details_tab'; 18import {DatasetSliceTrack} from '../../components/tracks/dataset_slice_track'; 19import {TrackEventDetailsPanel} from '../../public/details_panel'; 20import {Trace} from '../../public/trace'; 21import {SourceDataset} from '../../trace_processor/dataset'; 22import { 23 LONG, 24 LONG_NULL, 25 NUM, 26 STR_NULL, 27} from '../../trace_processor/query_result'; 28 29export interface TraceProcessorSliceTrackAttrs { 30 readonly trace: Trace; 31 readonly uri: string; 32 readonly maxDepth?: number; 33 readonly trackIds: ReadonlyArray<number>; 34 readonly detailsPanel?: (row: {id: number}) => TrackEventDetailsPanel; 35} 36 37export function createTraceProcessorSliceTrack({ 38 trace, 39 uri, 40 maxDepth, 41 trackIds, 42 detailsPanel, 43}: TraceProcessorSliceTrackAttrs) { 44 return new DatasetSliceTrack({ 45 trace, 46 uri, 47 dataset: new SourceDataset({ 48 schema: { 49 id: NUM, 50 ts: LONG, 51 dur: LONG, 52 name: STR_NULL, 53 depth: NUM, 54 thread_dur: LONG_NULL, 55 }, 56 src: 'slice', 57 filter: { 58 col: 'track_id', 59 in: trackIds, 60 }, 61 }), 62 sliceName: (row) => (row.name === null ? '[null]' : row.name), 63 initialMaxDepth: maxDepth, 64 rootTableName: 'slice', 65 queryGenerator: getDepthProvider(trackIds), 66 fillRatio: (row) => { 67 if (row.dur > 0n && row.thread_dur !== null) { 68 return clamp(BIMath.ratio(row.thread_dur, row.dur), 0, 1); 69 } else { 70 return 1; 71 } 72 }, 73 detailsPanel: detailsPanel 74 ? (row) => detailsPanel(row) 75 : () => new ThreadSliceDetailsPanel(trace), 76 }); 77} 78 79function getDepthProvider(trackIds: ReadonlyArray<number>) { 80 // If we have more than one track we basically just need to replace the query 81 // used for rendering tracks with this one which uses 82 // experimental_slice_layout. The reason we don't just put this query in the 83 // dataset is that the dataset is shared with the outside world and we don't 84 // want to force everyone else to use experimental_slice_track. 85 // TODO(stevegolton): Let's teach internal_layout how to mimic this behaviour. 86 if (trackIds.length > 1) { 87 return () => ` 88 select 89 id, 90 ts, 91 dur, 92 layout_depth as depth, 93 name, 94 thread_dur 95 from experimental_slice_layout 96 where filter_track_ids = '${trackIds.join(',')}' 97 `; 98 } else { 99 return undefined; 100 } 101} 102