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 { 16 createQueryCounterTrack, 17 SqlDataSource, 18} from '../../components/tracks/query_counter_track'; 19import {PerfettoPlugin} from '../../public/plugin'; 20import {Trace} from '../../public/trace'; 21import {TrackNode} from '../../public/workspace'; 22import {NUM_NULL} from '../../trace_processor/query_result'; 23import ProcessThreadGroupsPlugin from '../dev.perfetto.ProcessThreadGroups'; 24 25async function registerAllocsTrack( 26 ctx: Trace, 27 uri: string, 28 dataSource: SqlDataSource, 29) { 30 const track = await createQueryCounterTrack({ 31 trace: ctx, 32 uri, 33 data: dataSource, 34 }); 35 ctx.tracks.registerTrack({ 36 uri, 37 title: `dmabuf allocs`, 38 track: track, 39 }); 40} 41 42export default class implements PerfettoPlugin { 43 static readonly id = 'dev.perfetto.AndroidDmabuf'; 44 static readonly dependencies = [ProcessThreadGroupsPlugin]; 45 46 async onTraceLoad(ctx: Trace): Promise<void> { 47 const e = ctx.engine; 48 await e.query(`INCLUDE PERFETTO MODULE android.memory.dmabuf`); 49 await e.query(` 50 CREATE PERFETTO TABLE _android_memory_cumulative_dmabuf AS 51 SELECT 52 upid, utid, ts, 53 SUM(buf_size) OVER(PARTITION BY COALESCE(upid, utid) ORDER BY ts) AS value 54 FROM android_dmabuf_allocs;`); 55 56 const pids = await e.query( 57 `SELECT DISTINCT upid, IIF(upid IS NULL, utid, NULL) AS utid FROM _android_memory_cumulative_dmabuf`, 58 ); 59 const it = pids.iter({upid: NUM_NULL, utid: NUM_NULL}); 60 for (; it.valid(); it.next()) { 61 if (it.upid != null) { 62 const uri = `/android_process_dmabuf_upid_${it.upid}`; 63 const config: SqlDataSource = { 64 sqlSource: `SELECT ts, value FROM _android_memory_cumulative_dmabuf 65 WHERE upid = ${it.upid}`, 66 }; 67 await registerAllocsTrack(ctx, uri, config); 68 ctx.plugins 69 .getPlugin(ProcessThreadGroupsPlugin) 70 .getGroupForProcess(it.upid) 71 ?.addChildInOrder(new TrackNode({uri, title: 'dmabuf allocs'})); 72 } else if (it.utid != null) { 73 const uri = `/android_process_dmabuf_utid_${it.utid}`; 74 const config: SqlDataSource = { 75 sqlSource: `SELECT ts, value FROM _android_memory_cumulative_dmabuf 76 WHERE utid = ${it.utid}`, 77 }; 78 await registerAllocsTrack(ctx, uri, config); 79 ctx.plugins 80 .getPlugin(ProcessThreadGroupsPlugin) 81 .getGroupForThread(it.utid) 82 ?.addChildInOrder(new TrackNode({uri, title: 'dmabuf allocs'})); 83 } 84 } 85 } 86} 87