blob: f3704ace33c0bac27f0cdab287836e28bf66e7cf [file] [log] [blame]
// Copyright (C) 2024 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 {
expandProcessName,
FullTraceMetricData,
JankType,
MetricHandler,
} from './metricUtils';
import {Trace} from '../../../public/trace';
import {addDebugSliceTrack} from '../../../public/debug_tracks';
class FullTraceJankMetricHandler implements MetricHandler {
/**
* Matches metric key & return parsed data if successful.
*
* @param {string} metricKey The metric key to match.
* @returns {FullTraceMetricData | undefined} Parsed data or undefined if no match.
*/
public match(metricKey: string): FullTraceMetricData | undefined {
const matcher =
/perfetto_ft_(?<process>.*)-missed_(?<jankType>frames|sf_frames|app_frames)/;
const match = matcher.exec(metricKey);
if (!match?.groups) {
return undefined;
}
const metricData: FullTraceMetricData = {
process: expandProcessName(match.groups.process),
jankType: match.groups.jankType as JankType,
};
return metricData;
}
/**
* Adds the debug track for full trace jank metrics
*
* @param {FullTraceMetricData} metricData Parsed metric data for the full trace jank
* @param {Trace} ctx PluginContextTrace for trace related properties and methods
* @returns {void} Adds one track for Jank slice
*/
public async addMetricTrack(metricData: FullTraceMetricData, ctx: Trace) {
const INCLUDE_PREQUERY = `
INCLUDE PERFETTO MODULE android.frames.jank_type;
INCLUDE PERFETTO MODULE slices.slices;
`;
const config = this.fullTraceJankConfig(metricData);
await ctx.engine.query(INCLUDE_PREQUERY);
addDebugSliceTrack({trace: ctx, ...config});
}
private fullTraceJankConfig(metricData: FullTraceMetricData) {
let jankTypeFilter;
let jankTypeDisplayName;
if (metricData.jankType?.includes('app')) {
jankTypeFilter = ' android_is_app_jank_type(display_value)';
jankTypeDisplayName = 'app';
} else if (metricData.jankType?.includes('sf')) {
jankTypeFilter = ' android_is_sf_jank_type(display_value)';
jankTypeDisplayName = 'sf';
} else {
jankTypeFilter = " display_value != 'None'";
jankTypeDisplayName = 'all';
}
const processName = metricData.process;
// TODO: b/324245198 - Refactor when jank_type added to android_frame_stats
const fullTraceJankQuery = `
WITH filtered_args AS (
SELECT DISTINCT arg_set_id
FROM args
WHERE key = 'Jank type'
${jankTypeFilter ? 'AND ' + jankTypeFilter : ''}
)
SELECT
name,
ts as ts,
dur as dur,
track_id as track_id,
id as slice_id,
thread_dur as thread_dur,
category,
thread_name,
tid as tid,
process_name,
pid as pid
FROM _slice_with_thread_and_process_info
JOIN filtered_args ON filtered_args.arg_set_id = _slice_with_thread_and_process_info.arg_set_id
WHERE process_name = '${processName}'`;
const fullTraceJankColumns = [
'name',
'ts',
'dur',
'track_id',
'slice_id',
'thread_dur',
'category',
'thread_name',
'tid',
'process_name',
'pid',
];
const trackName = jankTypeDisplayName + ' missed frames in ' + processName;
return {
data: {
sqlSource: fullTraceJankQuery,
columns: fullTraceJankColumns,
},
columns: {ts: 'ts', dur: 'dur', name: 'name'},
argColumns: fullTraceJankColumns,
tableName: trackName,
};
}
}
export const pinFullTraceJankInstance = new FullTraceJankMetricHandler();