xref: /aosp_15_r20/external/perfetto/ui/src/plugins/dev.perfetto.Ftrace/index.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1// Copyright (C) 2023 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 m from 'mithril';
16import {FtraceExplorer, FtraceExplorerCache} from './ftrace_explorer';
17import {Engine} from '../../trace_processor/engine';
18import {Trace} from '../../public/trace';
19import {PerfettoPlugin} from '../../public/plugin';
20import {NUM} from '../../trace_processor/query_result';
21import {FtraceFilter, FtracePluginState} from './common';
22import {FtraceRawTrack} from './ftrace_track';
23import {TrackNode} from '../../public/workspace';
24
25const VERSION = 1;
26
27const DEFAULT_STATE: FtracePluginState = {
28  version: VERSION,
29  filter: {
30    excludeList: [],
31  },
32};
33
34export default class implements PerfettoPlugin {
35  static readonly id = 'dev.perfetto.Ftrace';
36  async onTraceLoad(ctx: Trace): Promise<void> {
37    const store = ctx.mountStore<FtracePluginState>((init: unknown) => {
38      if (
39        typeof init === 'object' &&
40        init !== null &&
41        'version' in init &&
42        init.version === VERSION
43      ) {
44        return init as {} as FtracePluginState;
45      } else {
46        return DEFAULT_STATE;
47      }
48    });
49    ctx.trash.use(store);
50
51    const filterStore = store.createSubStore(
52      ['filter'],
53      (x) => x as FtraceFilter,
54    );
55    ctx.trash.use(filterStore);
56
57    const cpus = await this.lookupCpuCores(ctx.engine);
58    const group = new TrackNode({
59      title: 'Ftrace Events',
60      sortOrder: -5,
61      isSummary: true,
62    });
63
64    for (const cpuNum of cpus) {
65      const uri = `/ftrace/cpu${cpuNum}`;
66      const title = `Ftrace Track for CPU ${cpuNum}`;
67
68      ctx.tracks.registerTrack({
69        uri,
70        title,
71        tags: {
72          cpu: cpuNum,
73          groupName: 'Ftrace Events',
74        },
75        track: new FtraceRawTrack(ctx.engine, cpuNum, filterStore),
76      });
77
78      const track = new TrackNode({uri, title});
79      group.addChildInOrder(track);
80    }
81
82    if (group.children.length) {
83      ctx.workspace.addChildInOrder(group);
84    }
85
86    const cache: FtraceExplorerCache = {
87      state: 'blank',
88      counters: [],
89    };
90
91    const ftraceTabUri = 'perfetto.FtraceRaw#FtraceEventsTab';
92
93    ctx.tabs.registerTab({
94      uri: ftraceTabUri,
95      isEphemeral: false,
96      content: {
97        render: () =>
98          m(FtraceExplorer, {
99            filterStore,
100            cache,
101            trace: ctx,
102          }),
103        getTitle: () => 'Ftrace Events',
104      },
105    });
106
107    ctx.commands.registerCommand({
108      id: 'perfetto.FtraceRaw#ShowFtraceTab',
109      name: 'Show ftrace tab',
110      callback: () => {
111        ctx.tabs.showTab(ftraceTabUri);
112      },
113    });
114  }
115
116  private async lookupCpuCores(engine: Engine): Promise<number[]> {
117    const query = 'select distinct cpu from ftrace_event order by cpu';
118
119    const result = await engine.query(query);
120    const it = result.iter({cpu: NUM});
121
122    const cpuCores: number[] = [];
123
124    for (; it.valid(); it.next()) {
125      cpuCores.push(it.cpu);
126    }
127
128    return cpuCores;
129  }
130}
131