blob: 55d182173ca3de6805e9ea0bfd550383cce26beb [file] [log] [blame]
paulsoumyadeep4fea3d02024-07-10 13:46:05 +00001// Copyright (C) 2024 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 {
16 expandProcessName,
17 FullTraceMetricData,
18 JankType,
19 MetricHandler,
20} from './metricUtils';
Primiano Tuccib2ee3142024-09-03 16:22:22 +010021import {Trace} from '../../../public/trace';
Nicolo' Mazzucato1438f282024-08-14 11:10:44 +000022import {addAndPinSliceTrack} from '../../dev.perfetto.AndroidCujs/trackUtils';
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000023import {SimpleSliceTrackConfig} from '../../../frontend/simple_slice_track';
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000024
25class FullTraceJankMetricHandler implements MetricHandler {
26 /**
27 * Matches metric key & return parsed data if successful.
28 *
29 * @param {string} metricKey The metric key to match.
30 * @returns {FullTraceMetricData | undefined} Parsed data or undefined if no match.
31 */
32 public match(metricKey: string): FullTraceMetricData | undefined {
33 const matcher =
34 /perfetto_ft_(?<process>.*)-missed_(?<jankType>frames|sf_frames|app_frames)/;
35 const match = matcher.exec(metricKey);
36 if (!match?.groups) {
37 return undefined;
38 }
39 const metricData: FullTraceMetricData = {
40 process: expandProcessName(match.groups.process),
41 jankType: match.groups.jankType as JankType,
42 };
43 return metricData;
44 }
45
46 /**
47 * Adds the debug track for full trace jank metrics
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000048 *
49 * @param {FullTraceMetricData} metricData Parsed metric data for the full trace jank
Primiano Tuccib2ee3142024-09-03 16:22:22 +010050 * @param {Trace} ctx PluginContextTrace for trace related properties and methods
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000051 * @returns {void} Adds one track for Jank slice
52 */
Primiano Tuccib2ee3142024-09-03 16:22:22 +010053 public async addMetricTrack(metricData: FullTraceMetricData, ctx: Trace) {
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000054 const INCLUDE_PREQUERY = `
55 INCLUDE PERFETTO MODULE android.frames.jank_type;
56 INCLUDE PERFETTO MODULE slices.slices;
57 `;
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000058 const {config: fullTraceJankConfig, trackName: trackName} =
59 this.fullTraceJankConfig(metricData);
60 await ctx.engine.query(INCLUDE_PREQUERY);
Nicolo' Mazzucato1438f282024-08-14 11:10:44 +000061 addAndPinSliceTrack(ctx, fullTraceJankConfig, trackName);
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000062 }
63
64 private fullTraceJankConfig(metricData: FullTraceMetricData): {
65 config: SimpleSliceTrackConfig;
66 trackName: string;
67 } {
68 let jankTypeFilter;
Nicolo' Mazzucato3ba30992024-09-03 14:36:35 +000069 let jankTypeDisplayName;
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000070 if (metricData.jankType?.includes('app')) {
71 jankTypeFilter = ' android_is_app_jank_type(display_value)';
72 jankTypeDisplayName = 'app';
73 } else if (metricData.jankType?.includes('sf')) {
74 jankTypeFilter = ' android_is_sf_jank_type(display_value)';
75 jankTypeDisplayName = 'sf';
Nicolo' Mazzucato3ba30992024-09-03 14:36:35 +000076 } else {
77 jankTypeFilter = " display_value != 'None'";
78 jankTypeDisplayName = 'all';
paulsoumyadeep4fea3d02024-07-10 13:46:05 +000079 }
80 const processName = metricData.process;
81
82 // TODO: b/324245198 - Refactor when jank_type added to android_frame_stats
83 const fullTraceJankQuery = `
84 WITH filtered_args AS (
85 SELECT DISTINCT arg_set_id
86 FROM args
87 WHERE key = 'Jank type'
88 ${jankTypeFilter ? 'AND ' + jankTypeFilter : ''}
89 )
90 SELECT
91 name,
92 ts as ts,
93 dur as dur,
94 track_id as track_id,
95 id as slice_id,
96 thread_dur as thread_dur,
97 category,
98 thread_name,
99 tid as tid,
100 process_name,
101 pid as pid
102 FROM _slice_with_thread_and_process_info
103 JOIN filtered_args ON filtered_args.arg_set_id = _slice_with_thread_and_process_info.arg_set_id
104 WHERE process_name = '${processName}'`;
105 const fullTraceJankColumns = [
106 'name',
107 'ts',
108 'dur',
109 'track_id',
110 'slice_id',
111 'thread_dur',
112 'category',
113 'thread_name',
114 'tid',
115 'process_name',
116 'pid',
117 ];
118 const fullTraceJankConfig: SimpleSliceTrackConfig = {
119 data: {
120 sqlSource: fullTraceJankQuery,
121 columns: fullTraceJankColumns,
122 },
123 columns: {ts: 'ts', dur: 'dur', name: 'name'},
124 argColumns: fullTraceJankColumns,
125 };
126
127 const trackName = jankTypeDisplayName + ' missed frames in ' + processName;
128
129 return {config: fullTraceJankConfig, trackName: trackName};
130 }
131}
132
133export const pinFullTraceJankInstance = new FullTraceJankMetricHandler();