Merge "Add CUJ trace parser to Winscope" into udc-dev am: aaa8dcd1f7

Original change: https://googleplex-android-review.googlesource.com/c/platform/development/+/23515819

Change-Id: I1b4bf62a75fa97a704bcb5658f859b20e63549a9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-06-02 13:11:38 +00:00
committed by Automerger Merge Worker
8 changed files with 182 additions and 7 deletions

View File

@@ -30,6 +30,7 @@ const TAG_ICON = 'details';
const TRACE_ERROR_ICON = 'warning';
const EVENT_LOG_ICON = 'description';
const TRANSITION_ICON = 'animation';
const CUJ_ICON = 'label';
interface TraceInfoMap {
[key: number]: {
@@ -161,4 +162,10 @@ export const TRACE_INFO: TraceInfoMap = {
color: '#EC407A',
downloadArchiveDir: 'transition',
},
[TraceType.CUJS]: {
name: 'Cujs',
icon: CUJ_ICON,
color: '#EC407A',
downloadArchiveDir: 'eventlog',
},
};

View File

@@ -16,6 +16,7 @@
import {FunctionUtils, OnProgressUpdateType} from 'common/function_utils';
import {ParserError, ParserFactory} from 'parsers/parser_factory';
import {TracesParserCujs} from 'parsers/traces_parser_cujs';
import {TracesParserTransitions} from 'parsers/traces_parser_transitions';
import {FrameMapper} from 'trace/frame_mapper';
import {LoadedTrace} from 'trace/loaded_trace';
@@ -43,9 +44,14 @@ class TracePipeline {
);
this.parsers = parsers.map((it) => it.parser);
const tracesParser = new TracesParserTransitions(this.parsers);
if (tracesParser.canProvideEntries()) {
this.parsers.push(tracesParser);
const tracesParsers = [
new TracesParserTransitions(this.parsers),
new TracesParserCujs(this.parsers),
];
for (const tracesParser of tracesParsers) {
if (tracesParser.canProvideEntries()) {
this.parsers.push(tracesParser);
}
}
for (const parser of parsers) {

View File

@@ -20,7 +20,7 @@ import {Timestamp, TimestampType} from 'trace/timestamp';
import {TraceFile} from 'trace/trace_file';
import {TraceType} from 'trace/trace_type';
abstract class AbstractParser implements Parser<object> {
abstract class AbstractParser<T extends object = object> implements Parser<object> {
protected traceFile: TraceFile;
protected decodedEntries: any[] = [];
private timestamps: Map<TimestampType, Timestamp[]> = new Map<TimestampType, Timestamp[]>();
@@ -78,7 +78,7 @@ abstract class AbstractParser implements Parser<object> {
return this.timestamps.get(type);
}
getEntry(index: number, timestampType: TimestampType): object {
getEntry(index: number, timestampType: TimestampType): T {
return this.processDecodedEntry(index, timestampType, this.decodedEntries[index]);
}

View File

@@ -19,7 +19,7 @@ import {RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp';
import {TraceType} from 'trace/trace_type';
import {AbstractParser} from './abstract_parser';
class ParserEventLog extends AbstractParser {
class ParserEventLog extends AbstractParser<Event> {
override getTraceType(): TraceType {
return TraceType.EVENT_LOG;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2023, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Cuj, CujTrace, EventLog, Transition} from 'trace/flickerlib/common';
import {Parser} from 'trace/parser';
import {Timestamp, TimestampType} from 'trace/timestamp';
import {TraceType} from 'trace/trace_type';
import {AbstractTracesParser} from './abstract_traces_parser';
import {ParserEventLog} from './parser_eventlog';
export class TracesParserCujs extends AbstractTracesParser<Transition> {
private readonly eventLogTrace: ParserEventLog | undefined;
private readonly descriptors: string[];
constructor(parsers: Array<Parser<object>>) {
super(parsers);
const eventlogTraces = this.parsers.filter((it) => it.getTraceType() === TraceType.EVENT_LOG);
if (eventlogTraces.length > 0) {
this.eventLogTrace = eventlogTraces[0] as ParserEventLog;
}
if (this.eventLogTrace !== undefined) {
this.descriptors = this.eventLogTrace.getDescriptors();
} else {
this.descriptors = [];
}
}
override canProvideEntries(): boolean {
return this.eventLogTrace !== undefined;
}
getLengthEntries(): number {
return this.getDecodedEntries().length;
}
getEntry(index: number, timestampType: TimestampType): Transition {
return this.getDecodedEntries()[index];
}
private cujTrace: CujTrace | undefined;
getDecodedEntries(): Cuj[] {
if (this.eventLogTrace === undefined) {
throw new Error('eventLogTrace not defined');
}
if (this.cujTrace === undefined) {
const events: Event[] = [];
for (let i = 0; i < this.eventLogTrace.getLengthEntries(); i++) {
events.push(this.eventLogTrace.getEntry(i, TimestampType.REAL));
}
this.cujTrace = new EventLog(events).cujTrace;
}
return this.cujTrace.entries;
}
override getDescriptors(): string[] {
return this.descriptors;
}
getTraceType(): TraceType {
return TraceType.CUJS;
}
override getTimestamp(type: TimestampType, transition: Transition): undefined | Timestamp {
if (type === TimestampType.ELAPSED) {
return new Timestamp(type, BigInt(transition.timestamp.elapsedNanos.toString()));
} else if (type === TimestampType.REAL) {
return new Timestamp(type, BigInt(transition.timestamp.unixNanos.toString()));
}
return undefined;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {assertDefined} from 'common/assert_utils';
import {UnitTestUtils} from 'test/unit/utils';
import {Cuj} from 'trace/flickerlib/common';
import {Parser} from 'trace/parser';
import {Timestamp, TimestampType} from 'trace/timestamp';
import {TraceType} from 'trace/trace_type';
import {TracesParserCujs} from './traces_parser_cujs';
describe('ParserCujs', () => {
let parser: Parser<Cuj>;
beforeAll(async () => {
const eventLogParser = assertDefined(
await UnitTestUtils.getParser('traces/eventlog.winscope')
) as Parser<Event>;
parser = new TracesParserCujs([eventLogParser]);
});
it('has expected trace type', () => {
expect(parser.getTraceType()).toEqual(TraceType.CUJS);
});
it('provides elapsed timestamps', () => {
const timestamps = parser.getTimestamps(TimestampType.ELAPSED)!;
expect(timestamps.length).toEqual(16);
const expected = [
new Timestamp(TimestampType.ELAPSED, 2661012770462n),
new Timestamp(TimestampType.ELAPSED, 2661012874914n),
new Timestamp(TimestampType.ELAPSED, 2661012903966n),
];
expect(timestamps.slice(0, 3)).toEqual(expected);
});
it('provides real timestamps', () => {
const expected = [
new Timestamp(TimestampType.REAL, 1681207048025446000n),
new Timestamp(TimestampType.REAL, 1681207048025551000n),
new Timestamp(TimestampType.REAL, 1681207048025580000n),
];
const timestamps = parser.getTimestamps(TimestampType.REAL)!;
expect(timestamps.length).toEqual(16);
expect(timestamps.slice(0, 3)).toEqual(expected);
});
});

View File

@@ -62,6 +62,8 @@ const Event = require('flicker').android.tools.common.traces.events.Event;
const FlickerEvent = require('flicker').android.tools.common.traces.events.FlickerEvent;
const FocusEvent = require('flicker').android.tools.common.traces.events.FocusEvent;
const EventLogParser = require('flicker').android.tools.common.parsers.events.EventLogParser;
const CujTrace = require('flicker').android.tools.common.parsers.events.CujTrace;
const Cuj = require('flicker').android.tools.common.parsers.events.Cuj;
// Transitions
const Transition = require('flicker').android.tools.common.traces.wm.Transition;
@@ -313,6 +315,8 @@ export {
FlickerEvent,
FocusEvent,
EventLogParser,
CujTrace,
Cuj,
// Transitions
Transition,
TransitionType,

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Event, Transition} from 'trace/flickerlib/common';
import {Cuj, Event, Transition} from 'trace/flickerlib/common';
import {LayerTraceEntry} from './flickerlib/layers/LayerTraceEntry';
import {WindowManagerState} from './flickerlib/windows/WindowManagerState';
import {LogMessage} from './protolog';
@@ -38,6 +38,7 @@ export enum TraceType {
WM_TRANSITION,
SHELL_TRANSITION,
TRANSITION,
CUJS,
TAG,
ERROR,
TEST_TRACE_STRING,
@@ -63,6 +64,7 @@ export interface TraceEntryTypeMap {
[TraceType.WM_TRANSITION]: object;
[TraceType.SHELL_TRANSITION]: object;
[TraceType.TRANSITION]: Transition;
[TraceType.CUJS]: Cuj;
[TraceType.TAG]: object;
[TraceType.ERROR]: object;
[TraceType.TEST_TRACE_STRING]: string;