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 {Timestamp} from 'common/time'; 18*90c8c64dSAndroid Build Coastguard Workerimport {AbsoluteFrameIndex} from './index_types'; 19*90c8c64dSAndroid Build Coastguard Workerimport {Trace} from './trace'; 20*90c8c64dSAndroid Build Coastguard Workerimport {TraceEntryTypeMap, TraceType} from './trace_type'; 21*90c8c64dSAndroid Build Coastguard Worker 22*90c8c64dSAndroid Build Coastguard Workerexport class Traces { 23*90c8c64dSAndroid Build Coastguard Worker private traces = new Set<Trace<{}>>(); 24*90c8c64dSAndroid Build Coastguard Worker 25*90c8c64dSAndroid Build Coastguard Worker addTrace(trace: Trace<{}>) { 26*90c8c64dSAndroid Build Coastguard Worker this.traces.add(trace); 27*90c8c64dSAndroid Build Coastguard Worker } 28*90c8c64dSAndroid Build Coastguard Worker 29*90c8c64dSAndroid Build Coastguard Worker getTrace<T extends TraceType>( 30*90c8c64dSAndroid Build Coastguard Worker type: T, 31*90c8c64dSAndroid Build Coastguard Worker ): Trace<TraceEntryTypeMap[T]> | undefined { 32*90c8c64dSAndroid Build Coastguard Worker let longestTraceWithMatchingType: Trace<{}> | undefined; 33*90c8c64dSAndroid Build Coastguard Worker this.traces.forEach((trace) => { 34*90c8c64dSAndroid Build Coastguard Worker if (trace.type !== type) { 35*90c8c64dSAndroid Build Coastguard Worker return; 36*90c8c64dSAndroid Build Coastguard Worker } 37*90c8c64dSAndroid Build Coastguard Worker 38*90c8c64dSAndroid Build Coastguard Worker // If multiple traces match the target type, return the longest one. 39*90c8c64dSAndroid Build Coastguard Worker // Assuming that covering this scenario is good enough (hopefully): 40*90c8c64dSAndroid Build Coastguard Worker // - Two traces have the same type because one is a dump (e.g. SF trace + dump) 41*90c8c64dSAndroid Build Coastguard Worker // - A viewer needs to access another trace (e.g. IME viewers accesses SF trace) 42*90c8c64dSAndroid Build Coastguard Worker if ( 43*90c8c64dSAndroid Build Coastguard Worker !longestTraceWithMatchingType || 44*90c8c64dSAndroid Build Coastguard Worker trace.lengthEntries > longestTraceWithMatchingType.lengthEntries 45*90c8c64dSAndroid Build Coastguard Worker ) { 46*90c8c64dSAndroid Build Coastguard Worker longestTraceWithMatchingType = trace; 47*90c8c64dSAndroid Build Coastguard Worker } 48*90c8c64dSAndroid Build Coastguard Worker }); 49*90c8c64dSAndroid Build Coastguard Worker return longestTraceWithMatchingType as 50*90c8c64dSAndroid Build Coastguard Worker | Trace<TraceEntryTypeMap[T]> 51*90c8c64dSAndroid Build Coastguard Worker | undefined; 52*90c8c64dSAndroid Build Coastguard Worker } 53*90c8c64dSAndroid Build Coastguard Worker 54*90c8c64dSAndroid Build Coastguard Worker getTraces<T extends TraceType>(type: T): Array<Trace<TraceEntryTypeMap[T]>> { 55*90c8c64dSAndroid Build Coastguard Worker return Array.from(this.traces).filter( 56*90c8c64dSAndroid Build Coastguard Worker (trace) => trace.type === type, 57*90c8c64dSAndroid Build Coastguard Worker ) as Array<Trace<TraceEntryTypeMap[T]>>; 58*90c8c64dSAndroid Build Coastguard Worker } 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Worker deleteTrace(trace: Trace<{}>) { 61*90c8c64dSAndroid Build Coastguard Worker this.traces.delete(trace); 62*90c8c64dSAndroid Build Coastguard Worker } 63*90c8c64dSAndroid Build Coastguard Worker 64*90c8c64dSAndroid Build Coastguard Worker hasTrace(trace: Trace<{}>) { 65*90c8c64dSAndroid Build Coastguard Worker return this.traces.has(trace); 66*90c8c64dSAndroid Build Coastguard Worker } 67*90c8c64dSAndroid Build Coastguard Worker 68*90c8c64dSAndroid Build Coastguard Worker sliceTime(start?: Timestamp, end?: Timestamp): Traces { 69*90c8c64dSAndroid Build Coastguard Worker const slice = new Traces(); 70*90c8c64dSAndroid Build Coastguard Worker this.traces.forEach((trace) => { 71*90c8c64dSAndroid Build Coastguard Worker slice.addTrace(trace.sliceTime(start, end)); 72*90c8c64dSAndroid Build Coastguard Worker }); 73*90c8c64dSAndroid Build Coastguard Worker return slice; 74*90c8c64dSAndroid Build Coastguard Worker } 75*90c8c64dSAndroid Build Coastguard Worker 76*90c8c64dSAndroid Build Coastguard Worker sliceFrames(start?: AbsoluteFrameIndex, end?: AbsoluteFrameIndex): Traces { 77*90c8c64dSAndroid Build Coastguard Worker const slice = new Traces(); 78*90c8c64dSAndroid Build Coastguard Worker this.traces.forEach((trace) => { 79*90c8c64dSAndroid Build Coastguard Worker slice.addTrace(trace.sliceFrames(start, end)); 80*90c8c64dSAndroid Build Coastguard Worker }); 81*90c8c64dSAndroid Build Coastguard Worker return slice; 82*90c8c64dSAndroid Build Coastguard Worker } 83*90c8c64dSAndroid Build Coastguard Worker 84*90c8c64dSAndroid Build Coastguard Worker forEachTrace(callback: (trace: Trace<{}>, type: TraceType) => void): void { 85*90c8c64dSAndroid Build Coastguard Worker this.traces.forEach((trace, type) => { 86*90c8c64dSAndroid Build Coastguard Worker callback(trace, trace.type); 87*90c8c64dSAndroid Build Coastguard Worker }); 88*90c8c64dSAndroid Build Coastguard Worker } 89*90c8c64dSAndroid Build Coastguard Worker 90*90c8c64dSAndroid Build Coastguard Worker mapTrace<T>(callback: (trace: Trace<{}>, type: TraceType) => T): T[] { 91*90c8c64dSAndroid Build Coastguard Worker const result: T[] = []; 92*90c8c64dSAndroid Build Coastguard Worker this.forEachTrace((trace, type) => { 93*90c8c64dSAndroid Build Coastguard Worker result.push(callback(trace, type)); 94*90c8c64dSAndroid Build Coastguard Worker }); 95*90c8c64dSAndroid Build Coastguard Worker return result; 96*90c8c64dSAndroid Build Coastguard Worker } 97*90c8c64dSAndroid Build Coastguard Worker 98*90c8c64dSAndroid Build Coastguard Worker forEachFrame( 99*90c8c64dSAndroid Build Coastguard Worker callback: (traces: Traces, index: AbsoluteFrameIndex) => void, 100*90c8c64dSAndroid Build Coastguard Worker ): void { 101*90c8c64dSAndroid Build Coastguard Worker let startFrameIndex: AbsoluteFrameIndex = Number.MAX_VALUE; 102*90c8c64dSAndroid Build Coastguard Worker let endFrameIndex: AbsoluteFrameIndex = Number.MIN_VALUE; 103*90c8c64dSAndroid Build Coastguard Worker 104*90c8c64dSAndroid Build Coastguard Worker this.traces.forEach((trace) => { 105*90c8c64dSAndroid Build Coastguard Worker const framesRange = trace.getFramesRange(); 106*90c8c64dSAndroid Build Coastguard Worker if (framesRange && framesRange.start < framesRange.end) { 107*90c8c64dSAndroid Build Coastguard Worker startFrameIndex = Math.min(startFrameIndex, framesRange.start); 108*90c8c64dSAndroid Build Coastguard Worker endFrameIndex = Math.max(endFrameIndex, framesRange.end); 109*90c8c64dSAndroid Build Coastguard Worker } 110*90c8c64dSAndroid Build Coastguard Worker }); 111*90c8c64dSAndroid Build Coastguard Worker 112*90c8c64dSAndroid Build Coastguard Worker for (let i = startFrameIndex; i < endFrameIndex; ++i) { 113*90c8c64dSAndroid Build Coastguard Worker callback(this.sliceFrames(i, i + 1), i); 114*90c8c64dSAndroid Build Coastguard Worker } 115*90c8c64dSAndroid Build Coastguard Worker } 116*90c8c64dSAndroid Build Coastguard Worker 117*90c8c64dSAndroid Build Coastguard Worker mapFrame<T>(callback: (traces: Traces, index: AbsoluteFrameIndex) => T): T[] { 118*90c8c64dSAndroid Build Coastguard Worker const result: T[] = []; 119*90c8c64dSAndroid Build Coastguard Worker this.forEachFrame((traces, index) => { 120*90c8c64dSAndroid Build Coastguard Worker result.push(callback(traces, index)); 121*90c8c64dSAndroid Build Coastguard Worker }); 122*90c8c64dSAndroid Build Coastguard Worker return result; 123*90c8c64dSAndroid Build Coastguard Worker } 124*90c8c64dSAndroid Build Coastguard Worker 125*90c8c64dSAndroid Build Coastguard Worker getSize(): number { 126*90c8c64dSAndroid Build Coastguard Worker return this.traces.size; 127*90c8c64dSAndroid Build Coastguard Worker } 128*90c8c64dSAndroid Build Coastguard Worker 129*90c8c64dSAndroid Build Coastguard Worker [Symbol.iterator]() { 130*90c8c64dSAndroid Build Coastguard Worker return this.traces.values(); 131*90c8c64dSAndroid Build Coastguard Worker } 132*90c8c64dSAndroid Build Coastguard Worker} 133