1// Copyright (C) 2021 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {Trace} from '../../public/trace'; 16import {PerfettoPlugin} from '../../public/plugin'; 17import {TrackNode} from '../../public/workspace'; 18import {NUM, STR} from '../../trace_processor/query_result'; 19import {createActualFramesTrack} from './actual_frames_track'; 20import {createExpectedFramesTrack} from './expected_frames_track'; 21import { 22 ACTUAL_FRAMES_SLICE_TRACK_KIND, 23 FrameSelectionAggregator, 24} from './frame_selection_aggregator'; 25import ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups'; 26import {createAggregationToTabAdaptor} from '../../components/aggregation_adapter'; 27 28// Build a standardized URI for a frames track 29function makeUri(upid: number, kind: 'expected_frames' | 'actual_frames') { 30 return `/process_${upid}/${kind}`; 31} 32 33export default class implements PerfettoPlugin { 34 static readonly id = 'dev.perfetto.Frames'; 35 static readonly dependencies = [ProcessThreadGroupsPlugin]; 36 37 async onTraceLoad(ctx: Trace): Promise<void> { 38 this.addExpectedFrames(ctx); 39 this.addActualFrames(ctx); 40 ctx.selection.registerAreaSelectionTab( 41 createAggregationToTabAdaptor(ctx, new FrameSelectionAggregator()), 42 ); 43 } 44 45 async addExpectedFrames(ctx: Trace): Promise<void> { 46 const {engine} = ctx; 47 const result = await engine.query(` 48 with summary as ( 49 select 50 pt.upid, 51 group_concat(id) AS track_ids, 52 count() AS track_count 53 from process_track pt 54 join _slice_track_summary USING (id) 55 where pt.type = 'android_expected_frame_timeline' 56 group by pt.upid 57 ) 58 select 59 t.upid, 60 t.track_ids as trackIds, 61 __max_layout_depth(t.track_count, t.track_ids) as maxDepth 62 from summary t 63 `); 64 65 const it = result.iter({ 66 upid: NUM, 67 trackIds: STR, 68 maxDepth: NUM, 69 }); 70 71 for (; it.valid(); it.next()) { 72 const upid = it.upid; 73 const rawTrackIds = it.trackIds; 74 const trackIds = rawTrackIds.split(',').map((v) => Number(v)); 75 const maxDepth = it.maxDepth; 76 77 const title = 'Expected Timeline'; 78 const uri = makeUri(upid, 'expected_frames'); 79 ctx.tracks.registerTrack({ 80 uri, 81 title, 82 track: createExpectedFramesTrack(ctx, uri, maxDepth, trackIds), 83 tags: { 84 trackIds, 85 upid, 86 }, 87 }); 88 const group = ctx.plugins 89 .getPlugin(ProcessThreadGroupsPlugin) 90 .getGroupForProcess(upid); 91 const track = new TrackNode({uri, title, sortOrder: -50}); 92 group?.addChildInOrder(track); 93 } 94 } 95 96 async addActualFrames(ctx: Trace): Promise<void> { 97 const {engine} = ctx; 98 const result = await engine.query(` 99 with summary as ( 100 select 101 pt.upid, 102 group_concat(id) AS track_ids, 103 count() AS track_count 104 from process_track pt 105 join _slice_track_summary USING (id) 106 where pt.type = 'android_actual_frame_timeline' 107 group by pt.upid 108 ) 109 select 110 t.upid, 111 t.track_ids as trackIds, 112 __max_layout_depth(t.track_count, t.track_ids) as maxDepth 113 from summary t 114 `); 115 116 const it = result.iter({ 117 upid: NUM, 118 trackIds: STR, 119 maxDepth: NUM, 120 }); 121 for (; it.valid(); it.next()) { 122 const upid = it.upid; 123 const rawTrackIds = it.trackIds; 124 const trackIds = rawTrackIds.split(',').map((v) => Number(v)); 125 const maxDepth = it.maxDepth; 126 127 const title = 'Actual Timeline'; 128 const uri = makeUri(upid, 'actual_frames'); 129 ctx.tracks.registerTrack({ 130 uri, 131 title, 132 track: createActualFramesTrack(ctx, uri, maxDepth, trackIds), 133 tags: { 134 upid, 135 trackIds, 136 kind: ACTUAL_FRAMES_SLICE_TRACK_KIND, 137 }, 138 }); 139 const group = ctx.plugins 140 .getPlugin(ProcessThreadGroupsPlugin) 141 .getGroupForProcess(upid); 142 const track = new TrackNode({uri, title, sortOrder: -50}); 143 group?.addChildInOrder(track); 144 } 145 } 146} 147