/* * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { BaseElement, element } from '../../../base-ui/BaseElement'; import LitSwitch, { LitSwitchChangeEvent } from '../../../base-ui/switch/lit-switch'; import { HiperfPluginConfig, ProfilerPluginConfig, TracePluginConfig } from './bean/ProfilerServiceTypes'; import { SpRecordTemplateHtml } from './SpRecordTemplate.html'; @element('sp-record-template') export class SpRecordTemplate extends BaseElement { static SCHEDULING_ANALYSIS_EVENT = [ 'sched/sched_wakeup', 'sched/sched_switch', 'sched/sched_wakeup_new', 'sched/sched_waking', 'sched/sched_process_exit', 'sched/sched_process_free', 'task/task_newtask', 'task/task_rename', 'power/cpu_frequency', 'power/cpu_idle', 'irq/irq_handler_entry', 'irq/irq_handler_exit', 'irq/softirq_entry', 'irq/softirq_exit', 'irq/softirq_raise', ]; static FRAME_TIMELINE_EVENTS = [ 'sched/sched_switch', 'sched/sched_wakeup', 'sched/sched_wakeup_new', 'sched/sched_waking', 'sched/sched_process_exit', 'sched/sched_process_free', 'sched/sched_process_free', 'task/task_rename', 'power/cpu_frequency', 'power/cpu_idle', 'power/suspend_resume', ]; static FRAME_TIMELINE_CATEGORIES_EVENT = [ 'ability', 'ace', 'app', 'ark', 'binder', 'disk', 'freq', 'graphic', 'idle', 'irq', 'memreclaim', 'mmc', 'multimodalinput', 'ohos', 'pagecache', 'rpc', 'sched', 'sync', 'window', 'workq', 'zaudio', 'zcamera', 'zimage', 'zmedia', ]; static HIPERF_DEFAULT_RECORD_ARGS = '-f 1000 -a --cpu-limit 100 -e hw-cpu-cycles,sched:sched_waking' + ' --call-stack dwarf --clockid monotonic --offcpu -m 256'; private frameTimeline: LitSwitch | undefined | null; private schedulingAnalysis: LitSwitch | undefined | null; private appStartup: LitSwitch | undefined | null; private taskPoolEl: LitSwitch | undefined | null; private dynamicEffectEl: LitSwitch | undefined | null; initElements(): void { this.frameTimeline = this.shadowRoot?.querySelector('#frame_timeline'); this.schedulingAnalysis = this.shadowRoot?.querySelector('#scheduling_analysis'); this.appStartup = this.shadowRoot?.querySelector('#app_startup'); this.taskPoolEl = this.shadowRoot?.querySelector('#task_pool'); this.dynamicEffectEl = this.shadowRoot?.querySelector('#dynamic_effect'); this.addProbeListener( this.frameTimeline!, this.schedulingAnalysis!, this.appStartup!, this.taskPoolEl!, this.dynamicEffectEl! ); } addProbeListener(...elements: HTMLElement[]): void { elements.forEach((element) => { element.addEventListener('change', (event: CustomEventInit) => { let detail = event.detail; if (detail!.checked) { this.dispatchEvent(new CustomEvent('addProbe', { detail: { elementId: element.getAttribute('name') } })); } else { this.dispatchEvent(new CustomEvent('delProbe', { detail: { elementId: element.getAttribute('name') } })); } }); }); } getTemplateConfig(): Array> { let config: Array> = []; let traceEventSet: string[] = []; let hiTraceCategories: string[] = []; let useFtracePlugin: boolean = false; if (this.frameTimeline?.checked || this.appStartup?.checked || this.dynamicEffectEl?.checked) { useFtracePlugin = true; SpRecordTemplate.FRAME_TIMELINE_CATEGORIES_EVENT.forEach((categories) => { if (hiTraceCategories.indexOf(categories) === -1) { hiTraceCategories.push(categories); } }); if (this.appStartup?.checked) { hiTraceCategories.push('musl'); config.push(this.createHiperfDefaultConfig()); } SpRecordTemplate.FRAME_TIMELINE_EVENTS.forEach((ev) => { if (traceEventSet.indexOf(ev) === -1) { traceEventSet.push(ev); } }); } useFtracePlugin = this.schedulingAnalysisConfig(useFtracePlugin, traceEventSet); useFtracePlugin = this.taskPoolElConfig(useFtracePlugin, hiTraceCategories); if (useFtracePlugin) { let tracePluginConfig: TracePluginConfig = { ftraceEvents: traceEventSet, hitraceCategories: hiTraceCategories, flushIntervalMs: 1000, hitraceApps: [], bufferSizeKb: 20480, debugOn: false, flushThresholdKb: 4096, clock: 'boot', tracePeriodMs: 200, parseKsyms: true, rawDataPrefix: '', traceDurationMs: 0, }; let htraceProfilerPluginConfig: ProfilerPluginConfig = { pluginName: 'ftrace-plugin', sampleInterval: 1000, configData: tracePluginConfig, }; config.push(htraceProfilerPluginConfig); } return config; } private schedulingAnalysisConfig(useFtracePlugin: boolean, traceEventSet: string[]): boolean { if (this.schedulingAnalysis?.checked) { useFtracePlugin = true; SpRecordTemplate.SCHEDULING_ANALYSIS_EVENT.forEach((event) => { if (traceEventSet.indexOf(event) < 0) { traceEventSet.push(event); } }); } return useFtracePlugin; } private taskPoolElConfig(useFtracePlugin: boolean, hitraceCategories: string[]): boolean { if (this.taskPoolEl!.checked) { useFtracePlugin = true; hitraceCategories.push('commonlibrary'); } return useFtracePlugin; } private createHiperfDefaultConfig(): ProfilerPluginConfig { let hiPerf: HiperfPluginConfig = { isRoot: false, outfileName: '/data/local/tmp/perf.data', recordArgs: SpRecordTemplate.HIPERF_DEFAULT_RECORD_ARGS, }; return { pluginName: 'hiperf-plugin', sampleInterval: 5000, configData: hiPerf, }; } initHtml(): string { return SpRecordTemplateHtml; } }