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 {TrackData} from '../../components/tracks/track_data'; 16import {PERF_SAMPLES_PROFILE_TRACK_KIND} from '../../public/track_kinds'; 17import {Trace} from '../../public/trace'; 18import {PerfettoPlugin} from '../../public/plugin'; 19import {NUM, NUM_NULL, STR_NULL} from '../../trace_processor/query_result'; 20import {assertExists} from '../../base/logging'; 21import { 22 ProcessPerfSamplesProfileTrack, 23 ThreadPerfSamplesProfileTrack, 24} from './perf_samples_profile_track'; 25import {getThreadUriPrefix} from '../../public/utils'; 26import {TrackNode} from '../../public/workspace'; 27import ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups'; 28 29export interface Data extends TrackData { 30 tsStarts: BigInt64Array; 31} 32 33function makeUriForProc(upid: number) { 34 return `/process_${upid}/perf_samples_profile`; 35} 36 37export default class implements PerfettoPlugin { 38 static readonly id = 'dev.perfetto.PerfSamplesProfile'; 39 static readonly dependencies = [ProcessThreadGroupsPlugin]; 40 41 async onTraceLoad(ctx: Trace): Promise<void> { 42 const pResult = await ctx.engine.query(` 43 select distinct upid 44 from perf_sample 45 join thread using (utid) 46 where callsite_id is not null and upid is not null 47 `); 48 for (const it = pResult.iter({upid: NUM}); it.valid(); it.next()) { 49 const upid = it.upid; 50 const uri = makeUriForProc(upid); 51 const title = `Process Callstacks`; 52 ctx.tracks.registerTrack({ 53 uri, 54 title, 55 tags: { 56 kind: PERF_SAMPLES_PROFILE_TRACK_KIND, 57 upid, 58 }, 59 track: new ProcessPerfSamplesProfileTrack(ctx, uri, upid), 60 }); 61 const group = ctx.plugins 62 .getPlugin(ProcessThreadGroupsPlugin) 63 .getGroupForProcess(upid); 64 const track = new TrackNode({uri, title, sortOrder: -40}); 65 group?.addChildInOrder(track); 66 } 67 const tResult = await ctx.engine.query(` 68 select distinct 69 utid, 70 tid, 71 thread.name as threadName, 72 upid 73 from perf_sample 74 join thread using (utid) 75 where callsite_id is not null 76 `); 77 for ( 78 const it = tResult.iter({ 79 utid: NUM, 80 tid: NUM, 81 threadName: STR_NULL, 82 upid: NUM_NULL, 83 }); 84 it.valid(); 85 it.next() 86 ) { 87 const {threadName, utid, tid, upid} = it; 88 const title = 89 threadName === null 90 ? `Thread Callstacks ${tid}` 91 : `${threadName} Callstacks ${tid}`; 92 const uri = `${getThreadUriPrefix(upid, utid)}_perf_samples_profile`; 93 ctx.tracks.registerTrack({ 94 uri, 95 title, 96 tags: { 97 kind: PERF_SAMPLES_PROFILE_TRACK_KIND, 98 utid, 99 upid: upid ?? undefined, 100 }, 101 track: new ThreadPerfSamplesProfileTrack(ctx, uri, utid), 102 }); 103 const group = ctx.plugins 104 .getPlugin(ProcessThreadGroupsPlugin) 105 .getGroupForThread(utid); 106 const track = new TrackNode({uri, title, sortOrder: -50}); 107 group?.addChildInOrder(track); 108 } 109 110 ctx.onTraceReady.addListener(async () => { 111 await selectPerfSample(ctx); 112 }); 113 } 114} 115 116async function selectPerfSample(ctx: Trace) { 117 const profile = await assertExists(ctx.engine).query(` 118 select upid 119 from perf_sample 120 join thread using (utid) 121 where callsite_id is not null 122 order by ts desc 123 limit 1 124 `); 125 if (profile.numRows() !== 1) return; 126 const row = profile.firstRow({upid: NUM}); 127 const upid = row.upid; 128 129 // Create an area selection over the first process with a perf samples track 130 ctx.selection.selectArea({ 131 start: ctx.traceInfo.start, 132 end: ctx.traceInfo.end, 133 trackUris: [makeUriForProc(upid)], 134 }); 135} 136