1// Copyright (C) 2021 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 {slowlyCountRows} from '../../common/query_iterator'; 16import {fromNs, toNs} from '../../common/time'; 17import { 18 TrackController, 19 trackControllerRegistry, 20} from '../../controller/track_controller'; 21 22import {Config, Data, EXPECTED_FRAMES_SLICE_TRACK_KIND} from './common'; 23 24class ExpectedFramesSliceTrackController extends TrackController<Config, Data> { 25 static readonly kind = EXPECTED_FRAMES_SLICE_TRACK_KIND; 26 private maxDurNs = 0; 27 28 async onBoundsChange(start: number, end: number, resolution: number): 29 Promise<Data> { 30 const startNs = toNs(start); 31 const endNs = toNs(end); 32 33 const pxSize = this.pxSize(); 34 35 // ns per quantization bucket (i.e. ns per pixel). /2 * 2 is to force it to 36 // be an even number, so we can snap in the middle. 37 const bucketNs = Math.max(Math.round(resolution * 1e9 * pxSize / 2) * 2, 1); 38 39 if (this.maxDurNs === 0) { 40 const maxDurResult = await this.query(` 41 select max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur)) 42 from experimental_slice_layout 43 where filter_track_ids = '${this.config.trackIds.join(',')}' 44 `); 45 if (slowlyCountRows(maxDurResult) === 1) { 46 this.maxDurNs = maxDurResult.columns[0].longValues![0]; 47 } 48 } 49 50 const rawResult = await this.query(` 51 SELECT 52 (ts + ${bucketNs / 2}) / ${bucketNs} * ${bucketNs} as tsq, 53 ts, 54 max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur)) as dur, 55 layout_depth, 56 name, 57 id, 58 dur = 0 as is_instant, 59 dur = -1 as is_incomplete 60 from experimental_slice_layout 61 where 62 filter_track_ids = '${this.config.trackIds.join(',')}' and 63 ts >= ${startNs - this.maxDurNs} and 64 ts <= ${endNs} 65 group by tsq, layout_depth 66 order by tsq, layout_depth 67 `); 68 69 const numRows = slowlyCountRows(rawResult); 70 const slices: Data = { 71 start, 72 end, 73 resolution, 74 length: numRows, 75 strings: [], 76 sliceIds: new Float64Array(numRows), 77 starts: new Float64Array(numRows), 78 ends: new Float64Array(numRows), 79 depths: new Uint16Array(numRows), 80 titles: new Uint16Array(numRows), 81 colors: new Uint16Array(numRows), 82 isInstant: new Uint16Array(numRows), 83 isIncomplete: new Uint16Array(numRows), 84 }; 85 86 const stringIndexes = new Map<string, number>(); 87 function internString(str: string) { 88 let idx = stringIndexes.get(str); 89 if (idx !== undefined) return idx; 90 idx = slices.strings.length; 91 slices.strings.push(str); 92 stringIndexes.set(str, idx); 93 return idx; 94 } 95 const greenIndex = internString('#4CAF50'); 96 97 const cols = rawResult.columns; 98 for (let row = 0; row < numRows; row++) { 99 const startNsQ = +cols[0].longValues![row]; 100 const startNs = +cols[1].longValues![row]; 101 const durNs = +cols[2].longValues![row]; 102 const endNs = startNs + durNs; 103 104 let endNsQ = Math.floor((endNs + bucketNs / 2 - 1) / bucketNs) * bucketNs; 105 endNsQ = Math.max(endNsQ, startNsQ + bucketNs); 106 107 if (startNsQ === endNsQ) { 108 throw new Error('Should never happen'); 109 } 110 111 slices.starts[row] = fromNs(startNsQ); 112 slices.ends[row] = fromNs(endNsQ); 113 slices.depths[row] = +cols[3].longValues![row]; 114 slices.titles[row] = internString(cols[4].stringValues![row]); 115 slices.sliceIds[row] = +cols[5].longValues![row]; 116 slices.isInstant[row] = +cols[6].longValues![row]; 117 slices.isIncomplete[row] = +cols[7].longValues![row]; 118 slices.colors![row] = greenIndex; 119 } 120 return slices; 121 } 122} 123 124 125trackControllerRegistry.register(ExpectedFramesSliceTrackController); 126