1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 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 */ 15 16import { BaseElement, element } from '../../../base-ui/BaseElement'; 17import LitSwitch, { LitSwitchChangeEvent } from '../../../base-ui/switch/lit-switch'; 18import { HiperfPluginConfig, ProfilerPluginConfig, TracePluginConfig } from './bean/ProfilerServiceTypes'; 19import { SpRecordTemplateHtml } from './SpRecordTemplate.html'; 20 21@element('sp-record-template') 22export class SpRecordTemplate extends BaseElement { 23 static SCHEDULING_ANALYSIS_EVENT = [ 24 'sched/sched_wakeup', 25 'sched/sched_switch', 26 'sched/sched_wakeup_new', 27 'sched/sched_waking', 28 'sched/sched_process_exit', 29 'sched/sched_process_free', 30 'task/task_newtask', 31 'task/task_rename', 32 'power/cpu_frequency', 33 'power/cpu_idle', 34 'irq/irq_handler_entry', 35 'irq/irq_handler_exit', 36 'irq/softirq_entry', 37 'irq/softirq_exit', 38 'irq/softirq_raise', 39 ]; 40 static FRAME_TIMELINE_EVENTS = [ 41 'sched/sched_switch', 42 'sched/sched_wakeup', 43 'sched/sched_wakeup_new', 44 'sched/sched_waking', 45 'sched/sched_process_exit', 46 'sched/sched_process_free', 47 'sched/sched_process_free', 48 'task/task_rename', 49 'power/cpu_frequency', 50 'power/cpu_idle', 51 'power/suspend_resume', 52 ]; 53 static FRAME_TIMELINE_CATEGORIES_EVENT = [ 54 'ability', 55 'ace', 56 'app', 57 'ark', 58 'binder', 59 'disk', 60 'freq', 61 'graphic', 62 'idle', 63 'irq', 64 'memreclaim', 65 'mmc', 66 'multimodalinput', 67 'ohos', 68 'pagecache', 69 'rpc', 70 'sched', 71 'sync', 72 'window', 73 'workq', 74 'zaudio', 75 'zcamera', 76 'zimage', 77 'zmedia', 78 ]; 79 static HIPERF_DEFAULT_RECORD_ARGS = 80 '-f 1000 -a --cpu-limit 100 -e hw-cpu-cycles,sched:sched_waking' + 81 ' --call-stack dwarf --clockid monotonic --offcpu -m 256'; 82 private frameTimeline: LitSwitch | undefined | null; 83 private schedulingAnalysis: LitSwitch | undefined | null; 84 private appStartup: LitSwitch | undefined | null; 85 private taskPoolEl: LitSwitch | undefined | null; 86 private dynamicEffectEl: LitSwitch | undefined | null; 87 88 initElements(): void { 89 this.frameTimeline = this.shadowRoot?.querySelector<LitSwitch>('#frame_timeline'); 90 this.schedulingAnalysis = this.shadowRoot?.querySelector<LitSwitch>('#scheduling_analysis'); 91 this.appStartup = this.shadowRoot?.querySelector<LitSwitch>('#app_startup'); 92 this.taskPoolEl = this.shadowRoot?.querySelector<LitSwitch>('#task_pool'); 93 this.dynamicEffectEl = this.shadowRoot?.querySelector<LitSwitch>('#dynamic_effect'); 94 this.addProbeListener( 95 this.frameTimeline!, 96 this.schedulingAnalysis!, 97 this.appStartup!, 98 this.taskPoolEl!, 99 this.dynamicEffectEl! 100 ); 101 } 102 103 addProbeListener(...elements: HTMLElement[]): void { 104 elements.forEach((element) => { 105 element.addEventListener('change', (event: CustomEventInit<LitSwitchChangeEvent>) => { 106 let detail = event.detail; 107 if (detail!.checked) { 108 this.dispatchEvent(new CustomEvent('addProbe', { detail: { elementId: element.getAttribute('name') } })); 109 } else { 110 this.dispatchEvent(new CustomEvent('delProbe', { detail: { elementId: element.getAttribute('name') } })); 111 } 112 }); 113 }); 114 } 115 116 getTemplateConfig(): Array<ProfilerPluginConfig<{}>> { 117 let config: Array<ProfilerPluginConfig<{}>> = []; 118 let traceEventSet: string[] = []; 119 let hiTraceCategories: string[] = []; 120 let useFtracePlugin: boolean = false; 121 if (this.frameTimeline?.checked || this.appStartup?.checked || this.dynamicEffectEl?.checked) { 122 useFtracePlugin = true; 123 SpRecordTemplate.FRAME_TIMELINE_CATEGORIES_EVENT.forEach((categories) => { 124 if (hiTraceCategories.indexOf(categories) === -1) { 125 hiTraceCategories.push(categories); 126 } 127 }); 128 if (this.appStartup?.checked) { 129 hiTraceCategories.push('musl'); 130 config.push(this.createHiperfDefaultConfig()); 131 } 132 SpRecordTemplate.FRAME_TIMELINE_EVENTS.forEach((ev) => { 133 if (traceEventSet.indexOf(ev) === -1) { 134 traceEventSet.push(ev); 135 } 136 }); 137 } 138 useFtracePlugin = this.schedulingAnalysisConfig(useFtracePlugin, traceEventSet); 139 useFtracePlugin = this.taskPoolElConfig(useFtracePlugin, hiTraceCategories); 140 if (useFtracePlugin) { 141 let tracePluginConfig: TracePluginConfig = { 142 ftraceEvents: traceEventSet, 143 hitraceCategories: hiTraceCategories, 144 flushIntervalMs: 1000, 145 hitraceApps: [], 146 bufferSizeKb: 20480, 147 debugOn: false, 148 flushThresholdKb: 4096, 149 clock: 'boot', 150 tracePeriodMs: 200, 151 parseKsyms: true, 152 rawDataPrefix: '', 153 traceDurationMs: 0, 154 }; 155 let htraceProfilerPluginConfig: ProfilerPluginConfig<TracePluginConfig> = { 156 pluginName: 'ftrace-plugin', 157 sampleInterval: 1000, 158 configData: tracePluginConfig, 159 }; 160 config.push(htraceProfilerPluginConfig); 161 } 162 return config; 163 } 164 165 private schedulingAnalysisConfig(useFtracePlugin: boolean, traceEventSet: string[]): boolean { 166 if (this.schedulingAnalysis?.checked) { 167 useFtracePlugin = true; 168 SpRecordTemplate.SCHEDULING_ANALYSIS_EVENT.forEach((event) => { 169 if (traceEventSet.indexOf(event) < 0) { 170 traceEventSet.push(event); 171 } 172 }); 173 } 174 return useFtracePlugin; 175 } 176 177 private taskPoolElConfig(useFtracePlugin: boolean, hitraceCategories: string[]): boolean { 178 if (this.taskPoolEl!.checked) { 179 useFtracePlugin = true; 180 hitraceCategories.push('commonlibrary'); 181 } 182 return useFtracePlugin; 183 } 184 185 private createHiperfDefaultConfig(): ProfilerPluginConfig<HiperfPluginConfig> { 186 let hiPerf: HiperfPluginConfig = { 187 isRoot: false, 188 outfileName: '/data/local/tmp/perf.data', 189 recordArgs: SpRecordTemplate.HIPERF_DEFAULT_RECORD_ARGS, 190 }; 191 return { 192 pluginName: 'hiperf-plugin', 193 sampleInterval: 5000, 194 configData: hiPerf, 195 }; 196 } 197 198 initHtml(): string { 199 return SpRecordTemplateHtml; 200 } 201} 202