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