xref: /aosp_15_r20/development/tools/winscope/src/trace/traces.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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