1*90c8c64dSAndroid Build Coastguard Worker/* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Workerimport {ArrayUtils} from 'common/array_utils'; 18*90c8c64dSAndroid Build Coastguard Workerimport {assertDefined} from 'common/assert_utils'; 19*90c8c64dSAndroid Build Coastguard Workerimport {INVALID_TIME_NS, Timestamp} from 'common/time'; 20*90c8c64dSAndroid Build Coastguard Workerimport {TimestampUtils} from 'common/timestamp_utils'; 21*90c8c64dSAndroid Build Coastguard Workerimport {TracesParserInput} from 'parsers/input/perfetto/traces_parser_input'; 22*90c8c64dSAndroid Build Coastguard Workerimport {AbstractParser as AbstractPerfettoParser} from 'parsers/perfetto/abstract_parser'; 23*90c8c64dSAndroid Build Coastguard Workerimport { 24*90c8c64dSAndroid Build Coastguard Worker CustomQueryParamTypeMap, 25*90c8c64dSAndroid Build Coastguard Worker CustomQueryParserResultTypeMap, 26*90c8c64dSAndroid Build Coastguard Worker CustomQueryResultTypeMap, 27*90c8c64dSAndroid Build Coastguard Worker CustomQueryType, 28*90c8c64dSAndroid Build Coastguard Worker ProcessParserResult, 29*90c8c64dSAndroid Build Coastguard Worker} from './custom_query'; 30*90c8c64dSAndroid Build Coastguard Workerimport {FrameMap} from './frame_map'; 31*90c8c64dSAndroid Build Coastguard Workerimport { 32*90c8c64dSAndroid Build Coastguard Worker AbsoluteEntryIndex, 33*90c8c64dSAndroid Build Coastguard Worker AbsoluteFrameIndex, 34*90c8c64dSAndroid Build Coastguard Worker EntriesRange, 35*90c8c64dSAndroid Build Coastguard Worker FramesRange, 36*90c8c64dSAndroid Build Coastguard Worker RelativeEntryIndex, 37*90c8c64dSAndroid Build Coastguard Worker} from './index_types'; 38*90c8c64dSAndroid Build Coastguard Workerimport {Parser} from './parser'; 39*90c8c64dSAndroid Build Coastguard Workerimport {TRACE_INFO} from './trace_info'; 40*90c8c64dSAndroid Build Coastguard Workerimport {TraceType} from './trace_type'; 41*90c8c64dSAndroid Build Coastguard Worker 42*90c8c64dSAndroid Build Coastguard Workerexport { 43*90c8c64dSAndroid Build Coastguard Worker AbsoluteEntryIndex, 44*90c8c64dSAndroid Build Coastguard Worker AbsoluteFrameIndex, 45*90c8c64dSAndroid Build Coastguard Worker EntriesRange, 46*90c8c64dSAndroid Build Coastguard Worker FramesRange, 47*90c8c64dSAndroid Build Coastguard Worker RelativeEntryIndex, 48*90c8c64dSAndroid Build Coastguard Worker} from './index_types'; 49*90c8c64dSAndroid Build Coastguard Worker 50*90c8c64dSAndroid Build Coastguard Workerexport abstract class TraceEntry<T> { 51*90c8c64dSAndroid Build Coastguard Worker constructor( 52*90c8c64dSAndroid Build Coastguard Worker protected readonly fullTrace: Trace<T>, 53*90c8c64dSAndroid Build Coastguard Worker protected readonly parser: Parser<T>, 54*90c8c64dSAndroid Build Coastguard Worker protected readonly index: AbsoluteEntryIndex, 55*90c8c64dSAndroid Build Coastguard Worker protected readonly timestamp: Timestamp, 56*90c8c64dSAndroid Build Coastguard Worker protected readonly framesRange: FramesRange | undefined, 57*90c8c64dSAndroid Build Coastguard Worker ) {} 58*90c8c64dSAndroid Build Coastguard Worker 59*90c8c64dSAndroid Build Coastguard Worker getFullTrace(): Trace<T> { 60*90c8c64dSAndroid Build Coastguard Worker return this.fullTrace; 61*90c8c64dSAndroid Build Coastguard Worker } 62*90c8c64dSAndroid Build Coastguard Worker 63*90c8c64dSAndroid Build Coastguard Worker getIndex(): AbsoluteEntryIndex { 64*90c8c64dSAndroid Build Coastguard Worker return this.index; 65*90c8c64dSAndroid Build Coastguard Worker } 66*90c8c64dSAndroid Build Coastguard Worker 67*90c8c64dSAndroid Build Coastguard Worker getTimestamp(): Timestamp { 68*90c8c64dSAndroid Build Coastguard Worker return this.timestamp; 69*90c8c64dSAndroid Build Coastguard Worker } 70*90c8c64dSAndroid Build Coastguard Worker 71*90c8c64dSAndroid Build Coastguard Worker hasValidTimestamp() { 72*90c8c64dSAndroid Build Coastguard Worker return this.timestamp.getValueNs() !== INVALID_TIME_NS; 73*90c8c64dSAndroid Build Coastguard Worker } 74*90c8c64dSAndroid Build Coastguard Worker 75*90c8c64dSAndroid Build Coastguard Worker getFramesRange(): FramesRange | undefined { 76*90c8c64dSAndroid Build Coastguard Worker if (!this.fullTrace.hasFrameInfo()) { 77*90c8c64dSAndroid Build Coastguard Worker throw new Error( 78*90c8c64dSAndroid Build Coastguard Worker `Trace ${ 79*90c8c64dSAndroid Build Coastguard Worker TRACE_INFO[this.fullTrace.type].name 80*90c8c64dSAndroid Build Coastguard Worker } can't be accessed in frame domain (no frame info available)`, 81*90c8c64dSAndroid Build Coastguard Worker ); 82*90c8c64dSAndroid Build Coastguard Worker } 83*90c8c64dSAndroid Build Coastguard Worker return this.framesRange; 84*90c8c64dSAndroid Build Coastguard Worker } 85*90c8c64dSAndroid Build Coastguard Worker 86*90c8c64dSAndroid Build Coastguard Worker abstract getValue(): any; 87*90c8c64dSAndroid Build Coastguard Worker} 88*90c8c64dSAndroid Build Coastguard Worker 89*90c8c64dSAndroid Build Coastguard Workerexport class TraceEntryLazy<T> extends TraceEntry<T> { 90*90c8c64dSAndroid Build Coastguard Worker constructor( 91*90c8c64dSAndroid Build Coastguard Worker fullTrace: Trace<T>, 92*90c8c64dSAndroid Build Coastguard Worker parser: Parser<T>, 93*90c8c64dSAndroid Build Coastguard Worker index: AbsoluteEntryIndex, 94*90c8c64dSAndroid Build Coastguard Worker timestamp: Timestamp, 95*90c8c64dSAndroid Build Coastguard Worker framesRange: FramesRange | undefined, 96*90c8c64dSAndroid Build Coastguard Worker ) { 97*90c8c64dSAndroid Build Coastguard Worker super(fullTrace, parser, index, timestamp, framesRange); 98*90c8c64dSAndroid Build Coastguard Worker } 99*90c8c64dSAndroid Build Coastguard Worker 100*90c8c64dSAndroid Build Coastguard Worker override async getValue(): Promise<T> { 101*90c8c64dSAndroid Build Coastguard Worker try { 102*90c8c64dSAndroid Build Coastguard Worker return await this.parser.getEntry(this.index); 103*90c8c64dSAndroid Build Coastguard Worker } catch (e) { 104*90c8c64dSAndroid Build Coastguard Worker this.fullTrace.setCorruptedState( 105*90c8c64dSAndroid Build Coastguard Worker true, 106*90c8c64dSAndroid Build Coastguard Worker `Cannot parse entry at index ${this.index}`, 107*90c8c64dSAndroid Build Coastguard Worker ); 108*90c8c64dSAndroid Build Coastguard Worker throw e; 109*90c8c64dSAndroid Build Coastguard Worker } 110*90c8c64dSAndroid Build Coastguard Worker } 111*90c8c64dSAndroid Build Coastguard Worker} 112*90c8c64dSAndroid Build Coastguard Worker 113*90c8c64dSAndroid Build Coastguard Workerexport class TraceEntryEager<T, U> extends TraceEntry<T> { 114*90c8c64dSAndroid Build Coastguard Worker private readonly value: U; 115*90c8c64dSAndroid Build Coastguard Worker 116*90c8c64dSAndroid Build Coastguard Worker constructor( 117*90c8c64dSAndroid Build Coastguard Worker fullTrace: Trace<T>, 118*90c8c64dSAndroid Build Coastguard Worker parser: Parser<T>, 119*90c8c64dSAndroid Build Coastguard Worker index: AbsoluteEntryIndex, 120*90c8c64dSAndroid Build Coastguard Worker timestamp: Timestamp, 121*90c8c64dSAndroid Build Coastguard Worker framesRange: FramesRange | undefined, 122*90c8c64dSAndroid Build Coastguard Worker value: U, 123*90c8c64dSAndroid Build Coastguard Worker ) { 124*90c8c64dSAndroid Build Coastguard Worker super(fullTrace, parser, index, timestamp, framesRange); 125*90c8c64dSAndroid Build Coastguard Worker this.value = value; 126*90c8c64dSAndroid Build Coastguard Worker } 127*90c8c64dSAndroid Build Coastguard Worker 128*90c8c64dSAndroid Build Coastguard Worker override getValue(): U { 129*90c8c64dSAndroid Build Coastguard Worker return this.value; 130*90c8c64dSAndroid Build Coastguard Worker } 131*90c8c64dSAndroid Build Coastguard Worker} 132*90c8c64dSAndroid Build Coastguard Worker 133*90c8c64dSAndroid Build Coastguard Workerexport class Trace<T> { 134*90c8c64dSAndroid Build Coastguard Worker readonly type: TraceType; 135*90c8c64dSAndroid Build Coastguard Worker readonly lengthEntries: number; 136*90c8c64dSAndroid Build Coastguard Worker 137*90c8c64dSAndroid Build Coastguard Worker private readonly parser: Parser<T>; 138*90c8c64dSAndroid Build Coastguard Worker private readonly descriptors: string[]; 139*90c8c64dSAndroid Build Coastguard Worker private readonly fullTrace: Trace<T>; 140*90c8c64dSAndroid Build Coastguard Worker private readonly entriesRange: EntriesRange; 141*90c8c64dSAndroid Build Coastguard Worker private frameMap?: FrameMap; 142*90c8c64dSAndroid Build Coastguard Worker private framesRange?: FramesRange; 143*90c8c64dSAndroid Build Coastguard Worker private corruptedState = false; 144*90c8c64dSAndroid Build Coastguard Worker private corruptedReason: string | undefined; 145*90c8c64dSAndroid Build Coastguard Worker 146*90c8c64dSAndroid Build Coastguard Worker static fromParser<T>(parser: Parser<T>): Trace<T> { 147*90c8c64dSAndroid Build Coastguard Worker return new Trace( 148*90c8c64dSAndroid Build Coastguard Worker parser.getTraceType(), 149*90c8c64dSAndroid Build Coastguard Worker parser, 150*90c8c64dSAndroid Build Coastguard Worker parser.getDescriptors(), 151*90c8c64dSAndroid Build Coastguard Worker undefined, 152*90c8c64dSAndroid Build Coastguard Worker undefined, 153*90c8c64dSAndroid Build Coastguard Worker ); 154*90c8c64dSAndroid Build Coastguard Worker } 155*90c8c64dSAndroid Build Coastguard Worker 156*90c8c64dSAndroid Build Coastguard Worker constructor( 157*90c8c64dSAndroid Build Coastguard Worker type: TraceType, 158*90c8c64dSAndroid Build Coastguard Worker parser: Parser<T>, 159*90c8c64dSAndroid Build Coastguard Worker descriptors: string[], 160*90c8c64dSAndroid Build Coastguard Worker fullTrace: Trace<T> | undefined, 161*90c8c64dSAndroid Build Coastguard Worker entriesRange: EntriesRange | undefined, 162*90c8c64dSAndroid Build Coastguard Worker ) { 163*90c8c64dSAndroid Build Coastguard Worker this.type = type; 164*90c8c64dSAndroid Build Coastguard Worker this.parser = parser; 165*90c8c64dSAndroid Build Coastguard Worker this.descriptors = descriptors; 166*90c8c64dSAndroid Build Coastguard Worker this.fullTrace = fullTrace ?? this; 167*90c8c64dSAndroid Build Coastguard Worker this.entriesRange = entriesRange ?? { 168*90c8c64dSAndroid Build Coastguard Worker start: 0, 169*90c8c64dSAndroid Build Coastguard Worker end: parser.getLengthEntries(), 170*90c8c64dSAndroid Build Coastguard Worker }; 171*90c8c64dSAndroid Build Coastguard Worker this.lengthEntries = this.entriesRange.end - this.entriesRange.start; 172*90c8c64dSAndroid Build Coastguard Worker } 173*90c8c64dSAndroid Build Coastguard Worker 174*90c8c64dSAndroid Build Coastguard Worker getDescriptors(): string[] { 175*90c8c64dSAndroid Build Coastguard Worker return this.parser.getDescriptors(); 176*90c8c64dSAndroid Build Coastguard Worker } 177*90c8c64dSAndroid Build Coastguard Worker 178*90c8c64dSAndroid Build Coastguard Worker getParser(): Parser<T> { 179*90c8c64dSAndroid Build Coastguard Worker return this.parser; 180*90c8c64dSAndroid Build Coastguard Worker } 181*90c8c64dSAndroid Build Coastguard Worker 182*90c8c64dSAndroid Build Coastguard Worker canSearch(): boolean { 183*90c8c64dSAndroid Build Coastguard Worker return [AbstractPerfettoParser, TracesParserInput].some( 184*90c8c64dSAndroid Build Coastguard Worker (ParserType) => this.parser instanceof ParserType, 185*90c8c64dSAndroid Build Coastguard Worker ); 186*90c8c64dSAndroid Build Coastguard Worker } 187*90c8c64dSAndroid Build Coastguard Worker 188*90c8c64dSAndroid Build Coastguard Worker setFrameInfo(frameMap: FrameMap, framesRange: FramesRange | undefined) { 189*90c8c64dSAndroid Build Coastguard Worker if (frameMap.lengthEntries !== this.fullTrace.lengthEntries) { 190*90c8c64dSAndroid Build Coastguard Worker throw new Error( 191*90c8c64dSAndroid Build Coastguard Worker `Attempted to set a frame map for ${ 192*90c8c64dSAndroid Build Coastguard Worker TRACE_INFO[this.type].name 193*90c8c64dSAndroid Build Coastguard Worker } trace with incompatible number of entries`, 194*90c8c64dSAndroid Build Coastguard Worker ); 195*90c8c64dSAndroid Build Coastguard Worker } 196*90c8c64dSAndroid Build Coastguard Worker this.frameMap = frameMap; 197*90c8c64dSAndroid Build Coastguard Worker this.framesRange = framesRange; 198*90c8c64dSAndroid Build Coastguard Worker } 199*90c8c64dSAndroid Build Coastguard Worker 200*90c8c64dSAndroid Build Coastguard Worker hasFrameInfo(): boolean { 201*90c8c64dSAndroid Build Coastguard Worker return this.frameMap !== undefined; 202*90c8c64dSAndroid Build Coastguard Worker } 203*90c8c64dSAndroid Build Coastguard Worker 204*90c8c64dSAndroid Build Coastguard Worker getEntry(index: RelativeEntryIndex): TraceEntryLazy<T> { 205*90c8c64dSAndroid Build Coastguard Worker return this.getEntryInternal(index, (index, timestamp, frames) => { 206*90c8c64dSAndroid Build Coastguard Worker return new TraceEntryLazy<T>( 207*90c8c64dSAndroid Build Coastguard Worker this.fullTrace, 208*90c8c64dSAndroid Build Coastguard Worker this.parser, 209*90c8c64dSAndroid Build Coastguard Worker index, 210*90c8c64dSAndroid Build Coastguard Worker timestamp, 211*90c8c64dSAndroid Build Coastguard Worker frames, 212*90c8c64dSAndroid Build Coastguard Worker ); 213*90c8c64dSAndroid Build Coastguard Worker }); 214*90c8c64dSAndroid Build Coastguard Worker } 215*90c8c64dSAndroid Build Coastguard Worker 216*90c8c64dSAndroid Build Coastguard Worker async customQuery<Q extends CustomQueryType>( 217*90c8c64dSAndroid Build Coastguard Worker type: Q, 218*90c8c64dSAndroid Build Coastguard Worker param?: CustomQueryParamTypeMap[Q], 219*90c8c64dSAndroid Build Coastguard Worker ): Promise<CustomQueryResultTypeMap<T>[Q]> { 220*90c8c64dSAndroid Build Coastguard Worker const makeTraceEntry = <U>( 221*90c8c64dSAndroid Build Coastguard Worker index: RelativeEntryIndex, 222*90c8c64dSAndroid Build Coastguard Worker value: U, 223*90c8c64dSAndroid Build Coastguard Worker ): TraceEntryEager<T, U> => { 224*90c8c64dSAndroid Build Coastguard Worker return this.getEntryInternal(index, (index, timestamp, frames) => { 225*90c8c64dSAndroid Build Coastguard Worker return new TraceEntryEager<T, U>( 226*90c8c64dSAndroid Build Coastguard Worker this.fullTrace, 227*90c8c64dSAndroid Build Coastguard Worker this.parser, 228*90c8c64dSAndroid Build Coastguard Worker index, 229*90c8c64dSAndroid Build Coastguard Worker timestamp, 230*90c8c64dSAndroid Build Coastguard Worker frames, 231*90c8c64dSAndroid Build Coastguard Worker value, 232*90c8c64dSAndroid Build Coastguard Worker ); 233*90c8c64dSAndroid Build Coastguard Worker }); 234*90c8c64dSAndroid Build Coastguard Worker }; 235*90c8c64dSAndroid Build Coastguard Worker 236*90c8c64dSAndroid Build Coastguard Worker const processParserResult = ProcessParserResult[type] as ( 237*90c8c64dSAndroid Build Coastguard Worker parserResult: CustomQueryParserResultTypeMap[Q], 238*90c8c64dSAndroid Build Coastguard Worker make: typeof makeTraceEntry, 239*90c8c64dSAndroid Build Coastguard Worker ) => CustomQueryResultTypeMap<T>[Q]; 240*90c8c64dSAndroid Build Coastguard Worker 241*90c8c64dSAndroid Build Coastguard Worker const parserResult = (await this.parser.customQuery( 242*90c8c64dSAndroid Build Coastguard Worker type, 243*90c8c64dSAndroid Build Coastguard Worker this.entriesRange, 244*90c8c64dSAndroid Build Coastguard Worker param, 245*90c8c64dSAndroid Build Coastguard Worker )) as CustomQueryParserResultTypeMap[Q]; 246*90c8c64dSAndroid Build Coastguard Worker const finalResult = processParserResult(parserResult, makeTraceEntry); 247*90c8c64dSAndroid Build Coastguard Worker return Promise.resolve(finalResult); 248*90c8c64dSAndroid Build Coastguard Worker } 249*90c8c64dSAndroid Build Coastguard Worker 250*90c8c64dSAndroid Build Coastguard Worker getFrame(frame: AbsoluteFrameIndex): Trace<T> { 251*90c8c64dSAndroid Build Coastguard Worker this.checkTraceCanBeAccessedInFrameDomain(); 252*90c8c64dSAndroid Build Coastguard Worker const entries = this.frameMap!.getEntriesRange({ 253*90c8c64dSAndroid Build Coastguard Worker start: frame, 254*90c8c64dSAndroid Build Coastguard Worker end: frame + 1, 255*90c8c64dSAndroid Build Coastguard Worker }); 256*90c8c64dSAndroid Build Coastguard Worker return this.createSlice(entries, {start: frame, end: frame + 1}); 257*90c8c64dSAndroid Build Coastguard Worker } 258*90c8c64dSAndroid Build Coastguard Worker 259*90c8c64dSAndroid Build Coastguard Worker findClosestEntry(time: Timestamp): TraceEntryLazy<T> | undefined { 260*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries === 0) { 261*90c8c64dSAndroid Build Coastguard Worker return undefined; 262*90c8c64dSAndroid Build Coastguard Worker } 263*90c8c64dSAndroid Build Coastguard Worker 264*90c8c64dSAndroid Build Coastguard Worker const entry = this.clampEntryToSliceBounds( 265*90c8c64dSAndroid Build Coastguard Worker ArrayUtils.binarySearchFirstGreaterOrEqual( 266*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps(), 267*90c8c64dSAndroid Build Coastguard Worker time, 268*90c8c64dSAndroid Build Coastguard Worker ), 269*90c8c64dSAndroid Build Coastguard Worker ); 270*90c8c64dSAndroid Build Coastguard Worker if (entry === undefined || entry === this.entriesRange.end) { 271*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(this.lengthEntries - 1); 272*90c8c64dSAndroid Build Coastguard Worker } 273*90c8c64dSAndroid Build Coastguard Worker 274*90c8c64dSAndroid Build Coastguard Worker if (entry === this.entriesRange.start) { 275*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(0); 276*90c8c64dSAndroid Build Coastguard Worker } 277*90c8c64dSAndroid Build Coastguard Worker 278*90c8c64dSAndroid Build Coastguard Worker const abs = (time: bigint) => (time < 0 ? -time : time); 279*90c8c64dSAndroid Build Coastguard Worker const timeDiff = abs( 280*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps()[entry].getValueNs() - time.getValueNs(), 281*90c8c64dSAndroid Build Coastguard Worker ); 282*90c8c64dSAndroid Build Coastguard Worker const prevEntry = entry - 1; 283*90c8c64dSAndroid Build Coastguard Worker const prevTimeDiff = abs( 284*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps()[prevEntry].getValueNs() - time.getValueNs(), 285*90c8c64dSAndroid Build Coastguard Worker ); 286*90c8c64dSAndroid Build Coastguard Worker if (prevTimeDiff < timeDiff) { 287*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(prevEntry - this.entriesRange.start); 288*90c8c64dSAndroid Build Coastguard Worker } 289*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(entry - this.entriesRange.start); 290*90c8c64dSAndroid Build Coastguard Worker } 291*90c8c64dSAndroid Build Coastguard Worker 292*90c8c64dSAndroid Build Coastguard Worker findFirstGreaterOrEqualEntry(time: Timestamp): TraceEntryLazy<T> | undefined { 293*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries === 0) { 294*90c8c64dSAndroid Build Coastguard Worker return undefined; 295*90c8c64dSAndroid Build Coastguard Worker } 296*90c8c64dSAndroid Build Coastguard Worker 297*90c8c64dSAndroid Build Coastguard Worker const pos = this.clampEntryToSliceBounds( 298*90c8c64dSAndroid Build Coastguard Worker ArrayUtils.binarySearchFirstGreaterOrEqual( 299*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps(), 300*90c8c64dSAndroid Build Coastguard Worker time, 301*90c8c64dSAndroid Build Coastguard Worker ), 302*90c8c64dSAndroid Build Coastguard Worker ); 303*90c8c64dSAndroid Build Coastguard Worker if (pos === undefined || pos === this.entriesRange.end) { 304*90c8c64dSAndroid Build Coastguard Worker return undefined; 305*90c8c64dSAndroid Build Coastguard Worker } 306*90c8c64dSAndroid Build Coastguard Worker 307*90c8c64dSAndroid Build Coastguard Worker const entry = this.getEntry(pos - this.entriesRange.start); 308*90c8c64dSAndroid Build Coastguard Worker if (entry.getTimestamp().getValueNs() < time.getValueNs()) { 309*90c8c64dSAndroid Build Coastguard Worker return undefined; 310*90c8c64dSAndroid Build Coastguard Worker } 311*90c8c64dSAndroid Build Coastguard Worker 312*90c8c64dSAndroid Build Coastguard Worker return entry; 313*90c8c64dSAndroid Build Coastguard Worker } 314*90c8c64dSAndroid Build Coastguard Worker 315*90c8c64dSAndroid Build Coastguard Worker findFirstGreaterEntry(time: Timestamp): TraceEntryLazy<T> | undefined { 316*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries === 0) { 317*90c8c64dSAndroid Build Coastguard Worker return undefined; 318*90c8c64dSAndroid Build Coastguard Worker } 319*90c8c64dSAndroid Build Coastguard Worker 320*90c8c64dSAndroid Build Coastguard Worker const pos = this.clampEntryToSliceBounds( 321*90c8c64dSAndroid Build Coastguard Worker ArrayUtils.binarySearchFirstGreater(this.getFullTraceTimestamps(), time), 322*90c8c64dSAndroid Build Coastguard Worker ); 323*90c8c64dSAndroid Build Coastguard Worker if (pos === undefined || pos === this.entriesRange.end) { 324*90c8c64dSAndroid Build Coastguard Worker return undefined; 325*90c8c64dSAndroid Build Coastguard Worker } 326*90c8c64dSAndroid Build Coastguard Worker 327*90c8c64dSAndroid Build Coastguard Worker const entry = this.getEntry(pos - this.entriesRange.start); 328*90c8c64dSAndroid Build Coastguard Worker if (entry.getTimestamp().getValueNs() <= time.getValueNs()) { 329*90c8c64dSAndroid Build Coastguard Worker return undefined; 330*90c8c64dSAndroid Build Coastguard Worker } 331*90c8c64dSAndroid Build Coastguard Worker 332*90c8c64dSAndroid Build Coastguard Worker return entry; 333*90c8c64dSAndroid Build Coastguard Worker } 334*90c8c64dSAndroid Build Coastguard Worker 335*90c8c64dSAndroid Build Coastguard Worker findLastLowerOrEqualEntry( 336*90c8c64dSAndroid Build Coastguard Worker timestamp: Timestamp, 337*90c8c64dSAndroid Build Coastguard Worker ): TraceEntryLazy<T> | undefined { 338*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries === 0) { 339*90c8c64dSAndroid Build Coastguard Worker return undefined; 340*90c8c64dSAndroid Build Coastguard Worker } 341*90c8c64dSAndroid Build Coastguard Worker const firstGreater = this.findFirstGreaterEntry(timestamp); 342*90c8c64dSAndroid Build Coastguard Worker if (!firstGreater) { 343*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(this.lengthEntries - 1); 344*90c8c64dSAndroid Build Coastguard Worker } 345*90c8c64dSAndroid Build Coastguard Worker if (firstGreater.getIndex() === this.entriesRange.start) { 346*90c8c64dSAndroid Build Coastguard Worker return undefined; 347*90c8c64dSAndroid Build Coastguard Worker } 348*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(firstGreater.getIndex() - this.entriesRange.start - 1); 349*90c8c64dSAndroid Build Coastguard Worker } 350*90c8c64dSAndroid Build Coastguard Worker 351*90c8c64dSAndroid Build Coastguard Worker findLastLowerEntry(timestamp: Timestamp): TraceEntryLazy<T> | undefined { 352*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries === 0) { 353*90c8c64dSAndroid Build Coastguard Worker return undefined; 354*90c8c64dSAndroid Build Coastguard Worker } 355*90c8c64dSAndroid Build Coastguard Worker const firstGreaterOrEqual = this.findFirstGreaterOrEqualEntry(timestamp); 356*90c8c64dSAndroid Build Coastguard Worker if (!firstGreaterOrEqual) { 357*90c8c64dSAndroid Build Coastguard Worker return this.getEntry(this.lengthEntries - 1); 358*90c8c64dSAndroid Build Coastguard Worker } 359*90c8c64dSAndroid Build Coastguard Worker if (firstGreaterOrEqual.getIndex() === this.entriesRange.start) { 360*90c8c64dSAndroid Build Coastguard Worker return undefined; 361*90c8c64dSAndroid Build Coastguard Worker } 362*90c8c64dSAndroid Build Coastguard Worker return this.getEntry( 363*90c8c64dSAndroid Build Coastguard Worker firstGreaterOrEqual.getIndex() - this.entriesRange.start - 1, 364*90c8c64dSAndroid Build Coastguard Worker ); 365*90c8c64dSAndroid Build Coastguard Worker } 366*90c8c64dSAndroid Build Coastguard Worker 367*90c8c64dSAndroid Build Coastguard Worker sliceEntries(start?: RelativeEntryIndex, end?: RelativeEntryIndex): Trace<T> { 368*90c8c64dSAndroid Build Coastguard Worker const startEntry = 369*90c8c64dSAndroid Build Coastguard Worker this.clampEntryToSliceBounds(this.convertToAbsoluteEntryIndex(start)) ?? 370*90c8c64dSAndroid Build Coastguard Worker this.entriesRange.start; 371*90c8c64dSAndroid Build Coastguard Worker const endEntry = 372*90c8c64dSAndroid Build Coastguard Worker this.clampEntryToSliceBounds(this.convertToAbsoluteEntryIndex(end)) ?? 373*90c8c64dSAndroid Build Coastguard Worker this.entriesRange.end; 374*90c8c64dSAndroid Build Coastguard Worker const entries: EntriesRange = { 375*90c8c64dSAndroid Build Coastguard Worker start: startEntry, 376*90c8c64dSAndroid Build Coastguard Worker end: endEntry, 377*90c8c64dSAndroid Build Coastguard Worker }; 378*90c8c64dSAndroid Build Coastguard Worker const frames = this.frameMap?.getFramesRange(entries); 379*90c8c64dSAndroid Build Coastguard Worker return this.createSlice(entries, frames); 380*90c8c64dSAndroid Build Coastguard Worker } 381*90c8c64dSAndroid Build Coastguard Worker 382*90c8c64dSAndroid Build Coastguard Worker sliceTime(start?: Timestamp, end?: Timestamp): Trace<T> { 383*90c8c64dSAndroid Build Coastguard Worker const startEntry = 384*90c8c64dSAndroid Build Coastguard Worker start === undefined 385*90c8c64dSAndroid Build Coastguard Worker ? this.entriesRange.start 386*90c8c64dSAndroid Build Coastguard Worker : this.clampEntryToSliceBounds( 387*90c8c64dSAndroid Build Coastguard Worker ArrayUtils.binarySearchFirstGreaterOrEqual( 388*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps(), 389*90c8c64dSAndroid Build Coastguard Worker start, 390*90c8c64dSAndroid Build Coastguard Worker ), 391*90c8c64dSAndroid Build Coastguard Worker ) ?? this.entriesRange.end; 392*90c8c64dSAndroid Build Coastguard Worker const endEntry = 393*90c8c64dSAndroid Build Coastguard Worker end === undefined 394*90c8c64dSAndroid Build Coastguard Worker ? this.entriesRange.end 395*90c8c64dSAndroid Build Coastguard Worker : this.clampEntryToSliceBounds( 396*90c8c64dSAndroid Build Coastguard Worker ArrayUtils.binarySearchFirstGreaterOrEqual( 397*90c8c64dSAndroid Build Coastguard Worker this.getFullTraceTimestamps(), 398*90c8c64dSAndroid Build Coastguard Worker end, 399*90c8c64dSAndroid Build Coastguard Worker ), 400*90c8c64dSAndroid Build Coastguard Worker ) ?? this.entriesRange.end; 401*90c8c64dSAndroid Build Coastguard Worker const entries: EntriesRange = { 402*90c8c64dSAndroid Build Coastguard Worker start: startEntry, 403*90c8c64dSAndroid Build Coastguard Worker end: endEntry, 404*90c8c64dSAndroid Build Coastguard Worker }; 405*90c8c64dSAndroid Build Coastguard Worker const frames = this.frameMap?.getFramesRange(entries); 406*90c8c64dSAndroid Build Coastguard Worker return this.createSlice(entries, frames); 407*90c8c64dSAndroid Build Coastguard Worker } 408*90c8c64dSAndroid Build Coastguard Worker 409*90c8c64dSAndroid Build Coastguard Worker sliceFrames(start?: AbsoluteFrameIndex, end?: AbsoluteFrameIndex): Trace<T> { 410*90c8c64dSAndroid Build Coastguard Worker this.checkTraceCanBeAccessedInFrameDomain(); 411*90c8c64dSAndroid Build Coastguard Worker if (!this.framesRange) { 412*90c8c64dSAndroid Build Coastguard Worker return this.createSlice(undefined, undefined); 413*90c8c64dSAndroid Build Coastguard Worker } 414*90c8c64dSAndroid Build Coastguard Worker const frames: FramesRange = { 415*90c8c64dSAndroid Build Coastguard Worker start: this.clampFrameToSliceBounds(start) ?? this.framesRange.start, 416*90c8c64dSAndroid Build Coastguard Worker end: this.clampFrameToSliceBounds(end) ?? this.framesRange.end, 417*90c8c64dSAndroid Build Coastguard Worker }; 418*90c8c64dSAndroid Build Coastguard Worker const entries = this.frameMap!.getEntriesRange(frames); 419*90c8c64dSAndroid Build Coastguard Worker return this.createSlice(entries, frames); 420*90c8c64dSAndroid Build Coastguard Worker } 421*90c8c64dSAndroid Build Coastguard Worker 422*90c8c64dSAndroid Build Coastguard Worker forEachEntry( 423*90c8c64dSAndroid Build Coastguard Worker callback: (pos: TraceEntryLazy<T>, index: RelativeEntryIndex) => void, 424*90c8c64dSAndroid Build Coastguard Worker ) { 425*90c8c64dSAndroid Build Coastguard Worker for (let index = 0; index < this.lengthEntries; ++index) { 426*90c8c64dSAndroid Build Coastguard Worker callback(this.getEntry(index), index); 427*90c8c64dSAndroid Build Coastguard Worker } 428*90c8c64dSAndroid Build Coastguard Worker } 429*90c8c64dSAndroid Build Coastguard Worker 430*90c8c64dSAndroid Build Coastguard Worker mapEntry<U>( 431*90c8c64dSAndroid Build Coastguard Worker callback: (entry: TraceEntryLazy<T>, index: RelativeEntryIndex) => U, 432*90c8c64dSAndroid Build Coastguard Worker ): U[] { 433*90c8c64dSAndroid Build Coastguard Worker const result: U[] = []; 434*90c8c64dSAndroid Build Coastguard Worker this.forEachEntry((entry, index) => { 435*90c8c64dSAndroid Build Coastguard Worker result.push(callback(entry, index)); 436*90c8c64dSAndroid Build Coastguard Worker }); 437*90c8c64dSAndroid Build Coastguard Worker return result; 438*90c8c64dSAndroid Build Coastguard Worker } 439*90c8c64dSAndroid Build Coastguard Worker 440*90c8c64dSAndroid Build Coastguard Worker forEachTimestamp( 441*90c8c64dSAndroid Build Coastguard Worker callback: (timestamp: Timestamp, index: RelativeEntryIndex) => void, 442*90c8c64dSAndroid Build Coastguard Worker ) { 443*90c8c64dSAndroid Build Coastguard Worker const timestamps = this.getFullTraceTimestamps(); 444*90c8c64dSAndroid Build Coastguard Worker for (let index = 0; index < this.lengthEntries; ++index) { 445*90c8c64dSAndroid Build Coastguard Worker callback(timestamps[this.entriesRange.start + index], index); 446*90c8c64dSAndroid Build Coastguard Worker } 447*90c8c64dSAndroid Build Coastguard Worker } 448*90c8c64dSAndroid Build Coastguard Worker 449*90c8c64dSAndroid Build Coastguard Worker forEachFrame(callback: (frame: Trace<T>, index: AbsoluteFrameIndex) => void) { 450*90c8c64dSAndroid Build Coastguard Worker this.checkTraceCanBeAccessedInFrameDomain(); 451*90c8c64dSAndroid Build Coastguard Worker if (!this.framesRange) { 452*90c8c64dSAndroid Build Coastguard Worker return; 453*90c8c64dSAndroid Build Coastguard Worker } 454*90c8c64dSAndroid Build Coastguard Worker for ( 455*90c8c64dSAndroid Build Coastguard Worker let frame = this.framesRange.start; 456*90c8c64dSAndroid Build Coastguard Worker frame < this.framesRange.end; 457*90c8c64dSAndroid Build Coastguard Worker ++frame 458*90c8c64dSAndroid Build Coastguard Worker ) { 459*90c8c64dSAndroid Build Coastguard Worker callback(this.getFrame(frame), frame); 460*90c8c64dSAndroid Build Coastguard Worker } 461*90c8c64dSAndroid Build Coastguard Worker } 462*90c8c64dSAndroid Build Coastguard Worker 463*90c8c64dSAndroid Build Coastguard Worker mapFrame<U>( 464*90c8c64dSAndroid Build Coastguard Worker callback: (frame: Trace<T>, index: AbsoluteFrameIndex) => U, 465*90c8c64dSAndroid Build Coastguard Worker ): U[] { 466*90c8c64dSAndroid Build Coastguard Worker const result: U[] = []; 467*90c8c64dSAndroid Build Coastguard Worker this.forEachFrame((traces, index) => { 468*90c8c64dSAndroid Build Coastguard Worker result.push(callback(traces, index)); 469*90c8c64dSAndroid Build Coastguard Worker }); 470*90c8c64dSAndroid Build Coastguard Worker return result; 471*90c8c64dSAndroid Build Coastguard Worker } 472*90c8c64dSAndroid Build Coastguard Worker 473*90c8c64dSAndroid Build Coastguard Worker getFramesRange(): FramesRange | undefined { 474*90c8c64dSAndroid Build Coastguard Worker this.checkTraceCanBeAccessedInFrameDomain(); 475*90c8c64dSAndroid Build Coastguard Worker return this.framesRange; 476*90c8c64dSAndroid Build Coastguard Worker } 477*90c8c64dSAndroid Build Coastguard Worker 478*90c8c64dSAndroid Build Coastguard Worker isDump(): boolean { 479*90c8c64dSAndroid Build Coastguard Worker return this.lengthEntries === 1; 480*90c8c64dSAndroid Build Coastguard Worker } 481*90c8c64dSAndroid Build Coastguard Worker 482*90c8c64dSAndroid Build Coastguard Worker isDumpWithoutTimestamp(): boolean { 483*90c8c64dSAndroid Build Coastguard Worker return this.isDump() && !this.getEntry(0).hasValidTimestamp(); 484*90c8c64dSAndroid Build Coastguard Worker } 485*90c8c64dSAndroid Build Coastguard Worker 486*90c8c64dSAndroid Build Coastguard Worker isCorrupted(): boolean { 487*90c8c64dSAndroid Build Coastguard Worker return this.corruptedState; 488*90c8c64dSAndroid Build Coastguard Worker } 489*90c8c64dSAndroid Build Coastguard Worker 490*90c8c64dSAndroid Build Coastguard Worker getCorruptedReason(): string | undefined { 491*90c8c64dSAndroid Build Coastguard Worker return this.corruptedReason; 492*90c8c64dSAndroid Build Coastguard Worker } 493*90c8c64dSAndroid Build Coastguard Worker 494*90c8c64dSAndroid Build Coastguard Worker setCorruptedState(value: boolean, reason?: string) { 495*90c8c64dSAndroid Build Coastguard Worker this.corruptedState = value; 496*90c8c64dSAndroid Build Coastguard Worker this.corruptedReason = reason; 497*90c8c64dSAndroid Build Coastguard Worker } 498*90c8c64dSAndroid Build Coastguard Worker 499*90c8c64dSAndroid Build Coastguard Worker spansMultipleDates(): boolean { 500*90c8c64dSAndroid Build Coastguard Worker if (this.lengthEntries > 0) { 501*90c8c64dSAndroid Build Coastguard Worker let firstTs: string | undefined; 502*90c8c64dSAndroid Build Coastguard Worker let i = 0; 503*90c8c64dSAndroid Build Coastguard Worker while (firstTs === undefined && i < this.lengthEntries) { 504*90c8c64dSAndroid Build Coastguard Worker const entry = this.getEntry(i); 505*90c8c64dSAndroid Build Coastguard Worker if (entry.hasValidTimestamp()) { 506*90c8c64dSAndroid Build Coastguard Worker firstTs = entry.getTimestamp().format(); 507*90c8c64dSAndroid Build Coastguard Worker break; 508*90c8c64dSAndroid Build Coastguard Worker } 509*90c8c64dSAndroid Build Coastguard Worker i++; 510*90c8c64dSAndroid Build Coastguard Worker } 511*90c8c64dSAndroid Build Coastguard Worker const firstDate = TimestampUtils.extractDateFromHumanTimestamp( 512*90c8c64dSAndroid Build Coastguard Worker assertDefined(firstTs), 513*90c8c64dSAndroid Build Coastguard Worker ); 514*90c8c64dSAndroid Build Coastguard Worker if (firstDate) { 515*90c8c64dSAndroid Build Coastguard Worker const lastDate = TimestampUtils.extractDateFromHumanTimestamp( 516*90c8c64dSAndroid Build Coastguard Worker this.getEntry(this.lengthEntries - 1) 517*90c8c64dSAndroid Build Coastguard Worker .getTimestamp() 518*90c8c64dSAndroid Build Coastguard Worker .format(), 519*90c8c64dSAndroid Build Coastguard Worker ); 520*90c8c64dSAndroid Build Coastguard Worker return firstDate !== lastDate; 521*90c8c64dSAndroid Build Coastguard Worker } 522*90c8c64dSAndroid Build Coastguard Worker } 523*90c8c64dSAndroid Build Coastguard Worker return false; 524*90c8c64dSAndroid Build Coastguard Worker } 525*90c8c64dSAndroid Build Coastguard Worker 526*90c8c64dSAndroid Build Coastguard Worker private getEntryInternal< 527*90c8c64dSAndroid Build Coastguard Worker EntryType extends TraceEntryLazy<T> | TraceEntryEager<T, any>, 528*90c8c64dSAndroid Build Coastguard Worker >( 529*90c8c64dSAndroid Build Coastguard Worker index: RelativeEntryIndex, 530*90c8c64dSAndroid Build Coastguard Worker makeEntry: ( 531*90c8c64dSAndroid Build Coastguard Worker absoluteIndex: AbsoluteEntryIndex, 532*90c8c64dSAndroid Build Coastguard Worker timestamp: Timestamp, 533*90c8c64dSAndroid Build Coastguard Worker frames: FramesRange | undefined, 534*90c8c64dSAndroid Build Coastguard Worker ) => EntryType, 535*90c8c64dSAndroid Build Coastguard Worker ): EntryType { 536*90c8c64dSAndroid Build Coastguard Worker const absoluteIndex = this.convertToAbsoluteEntryIndex( 537*90c8c64dSAndroid Build Coastguard Worker index, 538*90c8c64dSAndroid Build Coastguard Worker ) as AbsoluteEntryIndex; 539*90c8c64dSAndroid Build Coastguard Worker if ( 540*90c8c64dSAndroid Build Coastguard Worker absoluteIndex < this.entriesRange.start || 541*90c8c64dSAndroid Build Coastguard Worker absoluteIndex >= this.entriesRange.end 542*90c8c64dSAndroid Build Coastguard Worker ) { 543*90c8c64dSAndroid Build Coastguard Worker throw new Error( 544*90c8c64dSAndroid Build Coastguard Worker `${ 545*90c8c64dSAndroid Build Coastguard Worker TRACE_INFO[this.type].name 546*90c8c64dSAndroid Build Coastguard Worker } trace entry's index out of bounds. Input relative index: ${index}. Slice length: ${ 547*90c8c64dSAndroid Build Coastguard Worker this.lengthEntries 548*90c8c64dSAndroid Build Coastguard Worker }.`, 549*90c8c64dSAndroid Build Coastguard Worker ); 550*90c8c64dSAndroid Build Coastguard Worker } 551*90c8c64dSAndroid Build Coastguard Worker const timestamp = this.getFullTraceTimestamps()[absoluteIndex]; 552*90c8c64dSAndroid Build Coastguard Worker const frames = this.clampFramesRangeToSliceBounds( 553*90c8c64dSAndroid Build Coastguard Worker this.frameMap?.getFramesRange({ 554*90c8c64dSAndroid Build Coastguard Worker start: absoluteIndex, 555*90c8c64dSAndroid Build Coastguard Worker end: absoluteIndex + 1, 556*90c8c64dSAndroid Build Coastguard Worker }), 557*90c8c64dSAndroid Build Coastguard Worker ); 558*90c8c64dSAndroid Build Coastguard Worker return makeEntry(absoluteIndex, timestamp, frames); 559*90c8c64dSAndroid Build Coastguard Worker } 560*90c8c64dSAndroid Build Coastguard Worker 561*90c8c64dSAndroid Build Coastguard Worker private getFullTraceTimestamps(): Timestamp[] { 562*90c8c64dSAndroid Build Coastguard Worker const timestamps = this.parser.getTimestamps(); 563*90c8c64dSAndroid Build Coastguard Worker if (!timestamps) { 564*90c8c64dSAndroid Build Coastguard Worker throw new Error( 565*90c8c64dSAndroid Build Coastguard Worker `Timestamps expected to be available for this ${ 566*90c8c64dSAndroid Build Coastguard Worker TRACE_INFO[this.type].name 567*90c8c64dSAndroid Build Coastguard Worker } trace.`, 568*90c8c64dSAndroid Build Coastguard Worker ); 569*90c8c64dSAndroid Build Coastguard Worker } 570*90c8c64dSAndroid Build Coastguard Worker return timestamps; 571*90c8c64dSAndroid Build Coastguard Worker } 572*90c8c64dSAndroid Build Coastguard Worker 573*90c8c64dSAndroid Build Coastguard Worker private convertToAbsoluteEntryIndex( 574*90c8c64dSAndroid Build Coastguard Worker index: RelativeEntryIndex | undefined, 575*90c8c64dSAndroid Build Coastguard Worker ): AbsoluteEntryIndex | undefined { 576*90c8c64dSAndroid Build Coastguard Worker if (index === undefined) { 577*90c8c64dSAndroid Build Coastguard Worker return undefined; 578*90c8c64dSAndroid Build Coastguard Worker } 579*90c8c64dSAndroid Build Coastguard Worker if (index < 0) { 580*90c8c64dSAndroid Build Coastguard Worker return this.entriesRange.end + index; 581*90c8c64dSAndroid Build Coastguard Worker } 582*90c8c64dSAndroid Build Coastguard Worker return this.entriesRange.start + index; 583*90c8c64dSAndroid Build Coastguard Worker } 584*90c8c64dSAndroid Build Coastguard Worker 585*90c8c64dSAndroid Build Coastguard Worker private createSlice( 586*90c8c64dSAndroid Build Coastguard Worker entries: EntriesRange | undefined, 587*90c8c64dSAndroid Build Coastguard Worker frames: FramesRange | undefined, 588*90c8c64dSAndroid Build Coastguard Worker ): Trace<T> { 589*90c8c64dSAndroid Build Coastguard Worker entries = this.clampEntriesRangeToSliceBounds(entries); 590*90c8c64dSAndroid Build Coastguard Worker frames = this.clampFramesRangeToSliceBounds(frames); 591*90c8c64dSAndroid Build Coastguard Worker 592*90c8c64dSAndroid Build Coastguard Worker if (entries === undefined || entries.start >= entries.end) { 593*90c8c64dSAndroid Build Coastguard Worker entries = { 594*90c8c64dSAndroid Build Coastguard Worker start: this.entriesRange.end, 595*90c8c64dSAndroid Build Coastguard Worker end: this.entriesRange.end, 596*90c8c64dSAndroid Build Coastguard Worker }; 597*90c8c64dSAndroid Build Coastguard Worker } 598*90c8c64dSAndroid Build Coastguard Worker 599*90c8c64dSAndroid Build Coastguard Worker const slice = new Trace<T>( 600*90c8c64dSAndroid Build Coastguard Worker this.type, 601*90c8c64dSAndroid Build Coastguard Worker this.parser, 602*90c8c64dSAndroid Build Coastguard Worker this.descriptors, 603*90c8c64dSAndroid Build Coastguard Worker this.fullTrace, 604*90c8c64dSAndroid Build Coastguard Worker entries, 605*90c8c64dSAndroid Build Coastguard Worker ); 606*90c8c64dSAndroid Build Coastguard Worker 607*90c8c64dSAndroid Build Coastguard Worker if (this.frameMap) { 608*90c8c64dSAndroid Build Coastguard Worker slice.setFrameInfo(this.frameMap, frames); 609*90c8c64dSAndroid Build Coastguard Worker } 610*90c8c64dSAndroid Build Coastguard Worker 611*90c8c64dSAndroid Build Coastguard Worker return slice; 612*90c8c64dSAndroid Build Coastguard Worker } 613*90c8c64dSAndroid Build Coastguard Worker 614*90c8c64dSAndroid Build Coastguard Worker private clampEntriesRangeToSliceBounds( 615*90c8c64dSAndroid Build Coastguard Worker entries: EntriesRange | undefined, 616*90c8c64dSAndroid Build Coastguard Worker ): EntriesRange | undefined { 617*90c8c64dSAndroid Build Coastguard Worker if (entries === undefined) { 618*90c8c64dSAndroid Build Coastguard Worker return undefined; 619*90c8c64dSAndroid Build Coastguard Worker } 620*90c8c64dSAndroid Build Coastguard Worker return { 621*90c8c64dSAndroid Build Coastguard Worker start: this.clampEntryToSliceBounds(entries.start) as AbsoluteEntryIndex, 622*90c8c64dSAndroid Build Coastguard Worker end: this.clampEntryToSliceBounds(entries.end) as AbsoluteEntryIndex, 623*90c8c64dSAndroid Build Coastguard Worker }; 624*90c8c64dSAndroid Build Coastguard Worker } 625*90c8c64dSAndroid Build Coastguard Worker 626*90c8c64dSAndroid Build Coastguard Worker private clampFramesRangeToSliceBounds( 627*90c8c64dSAndroid Build Coastguard Worker frames: FramesRange | undefined, 628*90c8c64dSAndroid Build Coastguard Worker ): FramesRange | undefined { 629*90c8c64dSAndroid Build Coastguard Worker if (frames === undefined) { 630*90c8c64dSAndroid Build Coastguard Worker return undefined; 631*90c8c64dSAndroid Build Coastguard Worker } 632*90c8c64dSAndroid Build Coastguard Worker return { 633*90c8c64dSAndroid Build Coastguard Worker start: this.clampFrameToSliceBounds(frames.start) as AbsoluteFrameIndex, 634*90c8c64dSAndroid Build Coastguard Worker end: this.clampFrameToSliceBounds(frames.end) as AbsoluteFrameIndex, 635*90c8c64dSAndroid Build Coastguard Worker }; 636*90c8c64dSAndroid Build Coastguard Worker } 637*90c8c64dSAndroid Build Coastguard Worker 638*90c8c64dSAndroid Build Coastguard Worker private clampEntryToSliceBounds( 639*90c8c64dSAndroid Build Coastguard Worker entry: AbsoluteEntryIndex | undefined, 640*90c8c64dSAndroid Build Coastguard Worker ): AbsoluteEntryIndex | undefined { 641*90c8c64dSAndroid Build Coastguard Worker if (entry === undefined) { 642*90c8c64dSAndroid Build Coastguard Worker return undefined; 643*90c8c64dSAndroid Build Coastguard Worker } 644*90c8c64dSAndroid Build Coastguard Worker return Math.min( 645*90c8c64dSAndroid Build Coastguard Worker Math.max(entry, this.entriesRange.start), 646*90c8c64dSAndroid Build Coastguard Worker this.entriesRange.end, 647*90c8c64dSAndroid Build Coastguard Worker ); 648*90c8c64dSAndroid Build Coastguard Worker } 649*90c8c64dSAndroid Build Coastguard Worker 650*90c8c64dSAndroid Build Coastguard Worker private clampFrameToSliceBounds( 651*90c8c64dSAndroid Build Coastguard Worker frame: AbsoluteFrameIndex | undefined, 652*90c8c64dSAndroid Build Coastguard Worker ): AbsoluteFrameIndex | undefined { 653*90c8c64dSAndroid Build Coastguard Worker if (!this.framesRange || frame === undefined) { 654*90c8c64dSAndroid Build Coastguard Worker return undefined; 655*90c8c64dSAndroid Build Coastguard Worker } 656*90c8c64dSAndroid Build Coastguard Worker 657*90c8c64dSAndroid Build Coastguard Worker if (frame < 0) { 658*90c8c64dSAndroid Build Coastguard Worker throw new Error( 659*90c8c64dSAndroid Build Coastguard Worker `Absolute frame index cannot be negative. Found '${frame}'`, 660*90c8c64dSAndroid Build Coastguard Worker ); 661*90c8c64dSAndroid Build Coastguard Worker } 662*90c8c64dSAndroid Build Coastguard Worker 663*90c8c64dSAndroid Build Coastguard Worker return Math.min( 664*90c8c64dSAndroid Build Coastguard Worker Math.max(frame, this.framesRange.start), 665*90c8c64dSAndroid Build Coastguard Worker this.framesRange.end, 666*90c8c64dSAndroid Build Coastguard Worker ); 667*90c8c64dSAndroid Build Coastguard Worker } 668*90c8c64dSAndroid Build Coastguard Worker 669*90c8c64dSAndroid Build Coastguard Worker private checkTraceCanBeAccessedInFrameDomain() { 670*90c8c64dSAndroid Build Coastguard Worker if (!this.frameMap) { 671*90c8c64dSAndroid Build Coastguard Worker throw new Error( 672*90c8c64dSAndroid Build Coastguard Worker `Trace ${ 673*90c8c64dSAndroid Build Coastguard Worker TRACE_INFO[this.type].name 674*90c8c64dSAndroid Build Coastguard Worker } can't be accessed in frame domain (no frame mapping available)`, 675*90c8c64dSAndroid Build Coastguard Worker ); 676*90c8c64dSAndroid Build Coastguard Worker } 677*90c8c64dSAndroid Build Coastguard Worker } 678*90c8c64dSAndroid Build Coastguard Worker} 679