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 {TrackNode} from '../../public/workspace'; 16import {Trace} from '../../public/trace'; 17import {PerfettoPlugin} from '../../public/plugin'; 18import {createQueryCounterTrack} from '../../components/tracks/query_counter_track'; 19import {Engine} from '../../trace_processor/engine'; 20import {NUM} from '../../trace_processor/query_result'; 21 22export default class implements PerfettoPlugin { 23 static readonly id = 'dev.perfetto.Io'; 24 async onTraceLoad(ctx: Trace) { 25 await ctx.engine.query(`INCLUDE PERFETTO MODULE linux.block_io`); 26 const devices = await this.lookupDevices(ctx.engine); 27 const group = new TrackNode({ 28 title: 'Queued IO requests', 29 sortOrder: -5, 30 isSummary: true, 31 }); 32 for (const device of devices) { 33 const uri = `/queued_io_request_count/device_${device['id']}`; 34 const title = `dev major:${device['major']} minor:${device['minor']}`; 35 const track = await createQueryCounterTrack({ 36 trace: ctx, 37 uri, 38 data: { 39 sqlSource: 40 `SELECT ts, ops_in_queue_or_device as value 41 FROM linux_active_block_io_operations_by_device 42 WHERE dev = ${String(device['id'])}` 43 }, 44 }); 45 ctx.tracks.registerTrack({ 46 uri, 47 title, 48 tags: { 49 device: device['id'], 50 groupName: 'Queued IO requests', 51 }, 52 track, 53 }); 54 const node = new TrackNode({uri, title}); 55 group.addChildInOrder(node); 56 } 57 if (group.children.length) { 58 ctx.workspace.addChildInOrder(group); 59 } 60 } 61 62 private async lookupDevices(engine: Engine): Promise<{ [key: string]: number; }[]> { 63 const query =` 64 SELECT DISTINCT dev, linux_device_major_id(dev) as major, linux_device_minor_id(dev) as minor 65 FROM linux_active_block_io_operations_by_device ORDER BY dev`; 66 const result = await engine.query(query); 67 const it = result.iter({dev: NUM, major: NUM, minor: NUM}); 68 69 const devs: { [key: string]: number; }[] = []; 70 71 for (; it.valid(); it.next()) { 72 devs.push({'id': it.dev, 'major': it.major, 'minor': it.minor}); 73 } 74 75 return devs; 76 } 77} 78