blob: 6038b4d04f0b43dc22aba7c06241e63a98fe27a5 [file] [log] [blame] [edit]
// 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 {Trace} from '../../public/trace';
import {TrackNode} from '../../public/workspace';
import {PerfettoPlugin} from '../../public/plugin';
import StandardGroupsPlugin from '../dev.perfetto.StandardGroups';
import TraceProcessorTrackPlugin from '../dev.perfetto.TraceProcessorTrack';
import {NUM} from '../../trace_processor/query_result';
export default class implements PerfettoPlugin {
static readonly id = 'com.android.LargeScreensPerf';
static readonly dependencies = [
StandardGroupsPlugin,
TraceProcessorTrackPlugin,
];
async onTraceLoad(ctx: Trace): Promise<void> {
this.addFoldedStateTrackToDeviceState(ctx);
ctx.commands.registerCommand({
id: 'com.android.UnfoldLatencyTracks',
name: 'Organize unfold latency tracks',
callback: async () => {
this.pinCoreTracks(ctx);
this.addUnfoldMiscSection(ctx);
await this.addUnfoldDisplaySwitchingSection(ctx);
this.addUnfoldAnimationSection(ctx);
},
});
}
private addFoldedStateTrackToDeviceState(ctx: Trace) {
const foldedStateTrack = ctx.defaultWorkspace.flatTracks.find(
(t) => t.name == 'FoldedState',
);
if (foldedStateTrack) {
const deviceStateGroup = ctx.plugins
.getPlugin(StandardGroupsPlugin)
.getOrCreateStandardGroup(ctx.defaultWorkspace, 'DEVICE_STATE');
deviceStateGroup.addChildLast(foldedStateTrack);
}
}
private pinCoreTracks(ctx: Trace) {
ctx.currentWorkspace.flatTracks
.filter(
(track) =>
track.name == 'FoldedState' ||
track.name.includes('hingeAngle') ||
track.name.endsWith('UNFOLD>'),
)
.forEach((track) => track.pin());
}
private addUnfoldMiscSection(ctx: Trace) {
// section for tracks that don't fit neatly in other sections and are not so important to be pinned
const group = new TrackNode({name: 'Unfold misc'});
ctx.currentWorkspace.addChildFirst(group);
ctx.currentWorkspace.flatTracks
.filter(
(t) =>
t.name.startsWith('waitForAllWindowsDrawn') ||
t.name == 'Waiting for KeyguardDrawnCallback#onDrawn',
)
.map((t) => t.clone())
.forEach((track) => group.addChildLast(track));
}
private addUnfoldAnimationSection(ctx: Trace) {
const group = new TrackNode({name: 'Unfold animation'});
ctx.currentWorkspace.addChildFirst(group);
ctx.currentWorkspace.flatTracks
.filter(
(t) =>
t.name == 'FoldUpdate' ||
t.name.includes('UnfoldTransition') ||
t.name.includes('UnfoldLightRevealOverlayAnimation') ||
t.name.endsWith('UNFOLD_ANIM>'),
)
.map((t) => t.clone())
.forEach((track) => group.addChildLast(track));
}
private async addUnfoldDisplaySwitchingSection(ctx: Trace) {
const group = new TrackNode({name: 'Unfold display switching'});
ctx.currentWorkspace.addChildFirst(group);
const displayTracks = ctx.currentWorkspace.flatTracks.filter(
(t) =>
t.name.includes('android.display') ||
t.name.includes('Screen on blocked'),
);
const photonicModulatorTrack = await this.findPhotonicModulatorTrack(ctx);
if (photonicModulatorTrack != undefined) {
displayTracks.push(photonicModulatorTrack);
}
displayTracks
// sorting so that "android.display" tracks are next to each other
.sort((t1, t2) => t1.name.localeCompare(t2.name))
.map((t) => t.clone())
.forEach((t) => group.addChildFirst(t));
}
private async findPhotonicModulatorTrack(
ctx: Trace,
): Promise<TrackNode | undefined> {
const photonicModulatorTrackWithSetDisplayState = `
SELECT
DISTINCT thread_track.id
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
LEFT JOIN thread ON thread_track.utid = thread.utid
WHERE slice.name LIKE "setDisplayState%"
AND thread.name LIKE "PhotonicMod%"
`;
const result = await ctx.engine.query(
photonicModulatorTrackWithSetDisplayState,
);
if (result.numRows() === 0) return;
const trackId = result.iter({id: NUM}).id;
const track = ctx.tracks.findTrack((t) =>
t.tags?.trackIds?.includes(trackId),
);
if (!track?.uri) return;
return ctx.currentWorkspace.getTrackByUri(track.uri);
}
}