1// 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 {NUM, STR} from '../../trace_processor/query_result'; 16import {PerfettoPlugin} from '../../public/plugin'; 17import {Trace} from '../../public/trace'; 18import {TrackNode} from '../../public/workspace'; 19import {SLICE_TRACK_KIND} from '../../public/track_kinds'; 20import {createQuerySliceTrack} from '../../components/tracks/query_slice_track'; 21 22export default class implements PerfettoPlugin { 23 static readonly id = 'com.android.GpuWorkPeriod'; 24 25 async onTraceLoad(ctx: Trace): Promise<void> { 26 const {engine} = ctx; 27 const result = await engine.query(` 28 include perfetto module android.gpu.work_period; 29 30 with grouped_packages as materialized ( 31 select 32 uid, 33 group_concat(package_name, ',') as package_name, 34 count() as cnt 35 from package_list 36 group by uid 37 ) 38 select 39 t.id trackId, 40 t.uid as uid, 41 t.gpu_id as gpuId, 42 iif(g.cnt = 1, g.package_name, 'UID ' || t.uid) as packageName 43 from android_gpu_work_period_track t 44 left join grouped_packages g using (uid) 45 order by uid 46 `); 47 48 const it = result.iter({ 49 trackId: NUM, 50 uid: NUM, 51 gpuId: NUM, 52 packageName: STR, 53 }); 54 55 const workPeriodByGpu = new Map<number, TrackNode>(); 56 for (; it.valid(); it.next()) { 57 const {trackId, gpuId, uid, packageName} = it; 58 const uri = `/gpu_work_period_${gpuId}_${uid}`; 59 const track = await createQuerySliceTrack({ 60 trace: ctx, 61 uri, 62 data: { 63 sqlSource: ` 64 select ts, dur, name 65 from slice 66 where track_id = ${trackId} 67 `, 68 }, 69 }); 70 ctx.tracks.registerTrack({ 71 uri, 72 title: packageName, 73 tags: { 74 trackIds: [trackId], 75 kind: SLICE_TRACK_KIND, 76 }, 77 track, 78 }); 79 let workPeriod = workPeriodByGpu.get(gpuId); 80 if (workPeriod === undefined) { 81 workPeriod = new TrackNode({ 82 title: `GPU Work Period (GPU ${gpuId})`, 83 isSummary: true, 84 }); 85 workPeriodByGpu.set(gpuId, workPeriod); 86 ctx.workspace.addChildInOrder(workPeriod); 87 } 88 workPeriod.addChildInOrder(new TrackNode({title: packageName, uri})); 89 } 90 } 91} 92