blob: c78abf81a21f849f18505883bc83cbf2536a4cae [file] [log] [blame]
// 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 {PerfettoPlugin} from '../../public/plugin';
import {addDebugSliceTrack} from '../../public/debug_tracks';
import {addQueryResultsTab} from '../../public/lib/query_table/query_result_tab';
const PERF_TRACE_COUNTERS_PRECONDITION = `
SELECT
str_value
FROM metadata
WHERE
name = 'trace_config_pbtxt'
AND str_value GLOB '*ftrace_events: "perf_trace_counters/sched_switch_with_ctrs"*'
`;
export default class implements PerfettoPlugin {
static readonly id = 'dev.perfetto.AndroidPerfTraceCounters';
async onTraceLoad(ctx: Trace): Promise<void> {
const resp = await ctx.engine.query(PERF_TRACE_COUNTERS_PRECONDITION);
if (resp.numRows() === 0) return;
ctx.commands.registerCommand({
id: 'dev.perfetto.AndroidPerfTraceCounters#ThreadRuntimeIPC',
name: 'Add a track to show a thread runtime ipc',
callback: async (tid) => {
if (tid === undefined) {
tid = prompt('Enter a thread tid', '');
if (tid === null) return;
}
const sqlPrefix = `
WITH
sched_switch_ipc AS (
SELECT
ts,
EXTRACT_ARG(arg_set_id, 'prev_pid') AS tid,
EXTRACT_ARG(arg_set_id, 'prev_comm') AS thread_name,
EXTRACT_ARG(arg_set_id, 'inst') / (EXTRACT_ARG(arg_set_id, 'cyc') * 1.0) AS ipc,
EXTRACT_ARG(arg_set_id, 'inst') AS instruction,
EXTRACT_ARG(arg_set_id, 'cyc') AS cycle,
EXTRACT_ARG(arg_set_id, 'stallbm') AS stall_backend_mem,
EXTRACT_ARG(arg_set_id, 'l3dm') AS l3_cache_miss
FROM ftrace_event
WHERE name = 'sched_switch_with_ctrs' AND tid = ${tid}
),
target_thread_sched_slice AS (
SELECT s.*, t.tid, t.name FROM sched s LEFT JOIN thread t USING (utid)
WHERE t.tid = ${tid}
),
target_thread_ipc_slice AS (
SELECT
(
SELECT
ts
FROM target_thread_sched_slice ts
WHERE ts.tid = ssi.tid AND ts.ts < ssi.ts
ORDER BY ts.ts DESC
LIMIT 1
) AS ts,
(
SELECT
dur
FROM target_thread_sched_slice ts
WHERE ts.tid = ssi.tid AND ts.ts < ssi.ts
ORDER BY ts.ts DESC
LIMIT 1
) AS dur,
ssi.ipc,
ssi.instruction,
ssi.cycle,
ssi.stall_backend_mem,
ssi.l3_cache_miss
FROM sched_switch_ipc ssi
)
`;
await addDebugSliceTrack({
trace: ctx,
data: {
sqlSource:
sqlPrefix +
`
SELECT * FROM target_thread_ipc_slice WHERE ts IS NOT NULL`,
},
title: 'Rutime IPC:' + tid,
columns: {ts: 'ts', dur: 'dur', name: 'ipc'},
argColumns: [
'instruction',
'cycle',
'stall_backend_mem',
'l3_cache_miss',
],
});
addQueryResultsTab(ctx, {
query:
sqlPrefix +
`
SELECT
(sum(instruction) * 1.0 / sum(cycle)*1.0) AS avg_ipc,
sum(dur)/1e6 as total_runtime_ms,
sum(instruction) AS total_instructions,
sum(cycle) AS total_cycles,
sum(stall_backend_mem) as total_stall_backend_mem,
sum(l3_cache_miss) as total_l3_cache_miss
FROM target_thread_ipc_slice WHERE ts IS NOT NULL`,
title: 'target thread ipc statistic',
});
},
});
}
}