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