xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.Io/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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