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 { LitSelectV } from '../../../base-ui/select/LitSelectV';
18import { LitSelect } from '../../../base-ui/select/LitSelect';
19import { LitSlider } from '../../../base-ui/slider/LitSlider';
20import LitSwitch, { LitSwitchChangeEvent } from '../../../base-ui/switch/lit-switch';
21import '../../../base-ui/select/LitSelectV';
22import '../../../base-ui/select/LitSelect';
23
24import '../../../base-ui/switch/lit-switch';
25import { info } from '../../../log/Log';
26import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager';
27import { SpRecordTrace } from '../SpRecordTrace';
28import { SpApplication } from '../../SpApplication';
29import { LitSearch } from '../trace/search/Search';
30import { Cmd } from '../../../command/Cmd';
31import { CmdConstant } from '../../../command/CmdConstant';
32import { SpRecordPerfHtml } from './SpRecordPerf.html';
33
34@element('sp-record-perf')
35export class SpRecordPerf extends BaseElement {
36  private addOptionButton: HTMLButtonElement | undefined | null;
37  private processSelect: LitSelectV | undefined | null;
38  private processInput: HTMLInputElement | undefined | null;
39  private cpuSelect: LitSelectV | undefined | null;
40  private eventSelect: LitSelectV | undefined | null;
41
42  private frequencySetInput: HTMLInputElement | undefined | null;
43  private recordProcessInput: HTMLInputElement | undefined | null;
44  private offCPUSwitch: LitSwitch | undefined | null;
45  private kernelChainSwitch: LitSwitch | undefined | null;
46  private callSelect: LitSelect | undefined | null;
47  private sp: SpApplication | undefined;
48  private recordPerfSearch: LitSearch | undefined;
49  private inputCpu: HTMLInputElement | undefined;
50  private inputEvent: HTMLInputElement | undefined;
51  private cpuData: Array<string> = [];
52  private eventData: Array<string> = [];
53
54  get show(): boolean {
55    return this.hasAttribute('show');
56  }
57
58  set show(perfShow: boolean) {
59    if (perfShow) {
60      this.setAttribute('show', '');
61    } else {
62      this.removeAttribute('show');
63    }
64  }
65
66  set startSamp(perfStart: boolean) {
67    if (perfStart) {
68      this.setAttribute('startSamp', '');
69      this.recordProcessInput!.removeAttribute('readonly');
70    } else {
71      this.removeAttribute('startSamp');
72      this.recordProcessInput!.setAttribute('readonly', 'readonly');
73    }
74  }
75
76  get startSamp(): boolean {
77    return this.hasAttribute('startSamp');
78  }
79
80  getPerfConfig(): PerfConfig | undefined {
81    let recordPerfConfigVal = this.shadowRoot?.querySelectorAll<HTMLElement>('.config');
82    let perfConfig: PerfConfig = {
83      process: 'ALL',
84      cpu: 'select ALL',
85      eventList: 'NONE',
86      cpuPercent: 100,
87      frequency: 1000,
88      period: 1,
89      isOffCpu: true,
90      noInherit: false,
91      isKernelChain: true,
92      callStack: 'dwarf',
93      branch: 'none',
94      mmap: 256,
95      clockType: 'monotonic',
96    };
97    recordPerfConfigVal!.forEach((value) => {
98      perfConfig = this.getPerfConfigData(value, perfConfig);
99    });
100    info('perfConfig  is : ', perfConfig);
101    return perfConfig;
102  }
103
104  private getPerfConfigData(value: HTMLElement, perfConfig: PerfConfig): PerfConfig {
105    switch (value.title) {
106      case 'Process':
107        let processSelect = value as LitSelectV;
108        if (processSelect.all) {
109          perfConfig.process = 'ALL';
110          break;
111        }
112        perfConfig = this.perfConfigByProcess(processSelect, perfConfig);
113        break;
114      case 'CPU':
115        perfConfig = this.perfConfigByCPU(perfConfig, value as LitSelectV);
116        break;
117      case 'Event List':
118        perfConfig = this.perfConfigByEventList(perfConfig, value as LitSelectV);
119        break;
120      case 'CPU Percent':
121        perfConfig = this.perfConfigCpuPercent(perfConfig, value.parentElement!);
122        break;
123      case 'Frequency':
124        perfConfig = this.perfConfigByFrequency(perfConfig, value as HTMLInputElement);
125        break;
126      case 'Period':
127        perfConfig = this.perfConfigByPeriod(perfConfig, value as HTMLInputElement);
128        break;
129      case 'Off CPU':
130        perfConfig.isOffCpu = (value as LitSwitch).checked;
131        break;
132      case 'Kernel Chain':
133        perfConfig.isKernelChain = (value as LitSwitch).checked;
134        break;
135      case 'No Inherit':
136        perfConfig.noInherit = (value as LitSwitch).checked;
137        break;
138      case 'Call Stack':
139        perfConfig = this.perfConfigByCallStack(perfConfig, value as LitSelect);
140        break;
141      case 'Branch':
142        perfConfig = this.perfConfigByBranch(perfConfig, value as LitSelect);
143        break;
144      case 'Mmap Pages':
145        perfConfig = this.perfConfigByMmapPages(perfConfig, value.parentElement!);
146        break;
147      case 'Clock Type':
148        perfConfig = this.perfConfigByClockType(perfConfig, value as LitSelect);
149        break;
150    }
151    return perfConfig;
152  }
153
154  private perfConfigByProcess(processSelect: LitSelectV, perfConfig: PerfConfig): PerfConfig {
155    if (processSelect.value.length > 0) {
156      let result = processSelect.value.match(/\((.+?)\)/g);
157      if (result) {
158        perfConfig.process = result.toString().replace(/[()]/g, '');
159      } else {
160        perfConfig.process = processSelect.value;
161      }
162    }
163    return perfConfig;
164  }
165
166  private perfConfigByCPU(perfConfig: PerfConfig, selectValue: LitSelectV): PerfConfig {
167    if (selectValue.value.length > 0) {
168      perfConfig.cpu = selectValue.value;
169    }
170    return perfConfig;
171  }
172
173  private perfConfigByEventList(perfConfig: PerfConfig, selectValue: LitSelectV): PerfConfig {
174    if (selectValue.value.length > 0) {
175      perfConfig.eventList = selectValue.value.replace(/\s/g, ',');
176    }
177    return perfConfig;
178  }
179
180  private perfConfigCpuPercent(perfConfig: PerfConfig, parEle: HTMLElement): PerfConfig {
181    if (parEle!.hasAttribute('percent')) {
182      let percent = parEle!.getAttribute('percent');
183      perfConfig.cpuPercent = Number(percent);
184    }
185    return perfConfig;
186  }
187
188  private perfConfigByFrequency(perfConfig: PerfConfig, elValue: HTMLInputElement): PerfConfig {
189    if (elValue.value !== '') {
190      perfConfig.frequency = Number(elValue.value);
191    }
192    return perfConfig;
193  }
194
195  private perfConfigByPeriod(perfConfig: PerfConfig, elValue: HTMLInputElement): PerfConfig {
196    if (elValue.value !== '') {
197      perfConfig.period = Number(elValue.value);
198    }
199    return perfConfig;
200  }
201
202  private perfConfigByCallStack(perfConfig: PerfConfig, callStack: LitSelect): PerfConfig {
203    if (callStack.value !== '') {
204      perfConfig.callStack = callStack.value;
205    }
206    return perfConfig;
207  }
208
209  private perfConfigByBranch(perfConfig: PerfConfig, branch: LitSelect): PerfConfig {
210    if (branch.value !== '') {
211      perfConfig.branch = branch.value;
212    }
213    return perfConfig;
214  }
215
216  private perfConfigByMmapPages(perfConfig: PerfConfig, parent: HTMLElement): PerfConfig {
217    if (parent!.hasAttribute('percent')) {
218      let pagesPercent = parent!.getAttribute('percent');
219      perfConfig.mmap = Math.pow(2, Number(pagesPercent));
220    }
221    return perfConfig;
222  }
223
224  private perfConfigByClockType(perfConfig: PerfConfig, clock: LitSelect): PerfConfig {
225    if (clock.value !== '') {
226      perfConfig.clockType = clock.value;
227    }
228    return perfConfig;
229  }
230
231  private initRecordPerfConfig(): void {
232    let recordPerfConfigList = this.shadowRoot?.querySelector<HTMLDivElement>('.configList');
233    this.addOptionButton = this.shadowRoot?.querySelector<HTMLButtonElement>('#addOptions');
234    perfConfigList.forEach((config) => {
235      let recordPerfDiv = document.createElement('div');
236      if (config.hidden) {
237        recordPerfDiv.className = 'record-perf-config-div hidden';
238      } else {
239        recordPerfDiv.className = 'record-perf-config-div';
240      }
241      let recordPerfHeadDiv = document.createElement('div');
242      recordPerfDiv.appendChild(recordPerfHeadDiv);
243      let recordPerfTitle = document.createElement('span');
244      recordPerfTitle.className = 'record-perf-title';
245      recordPerfTitle.textContent = config.title;
246      recordPerfHeadDiv.appendChild(recordPerfTitle);
247      let recordPerfDes = document.createElement('span');
248      recordPerfDes.textContent = config.des;
249      recordPerfDes.className = 'record-perf-des';
250      recordPerfHeadDiv.appendChild(recordPerfDes);
251      switch (config.type) {
252        case 'select-multiple':
253          this.configTypeBySelectMultiple(config, recordPerfDiv);
254          break;
255        case 'lit-slider':
256          this.configTypeByLitSlider(config, recordPerfDiv);
257          break;
258        case 'Mmap-lit-slider':
259          this.configTypeByMmapLitSlider(config, recordPerfDiv);
260          break;
261        case 'input':
262          this.configTypeByInput(config, recordPerfDiv);
263          break;
264        case 'select':
265          this.configTypeBySelect(config, recordPerfDiv);
266          break;
267        case 'switch':
268          this.configTypeBySwitch(config, recordPerfHeadDiv);
269          break;
270        default:
271          break;
272      }
273      recordPerfConfigList!.appendChild(recordPerfDiv);
274    });
275  }
276
277  processSelectMousedownHandler = (): void => {
278    if (SpRecordTrace.serialNumber === '') {
279      this.processSelect!.dataSource([], 'ALL-Process');
280    } else {
281      if (this.sp!.search) {
282        this.sp!.search = false;
283        this.recordPerfSearch!.clear();
284      }
285      Cmd.getProcess().then(
286        (processList) => {
287          this.processSelect?.dataSource(processList, 'ALL-Process');
288        },
289        () => {
290          this.sp!.search = true;
291          this.recordPerfSearch!.clear();
292          this.recordPerfSearch!.setPercent('please kill other hdc-server !', -2);
293        }
294      );
295    }
296  };
297
298  cpuSelectMouseDownHandler = (): void => {
299    if (SpRecordTrace.serialNumber === '') {
300      this.cpuSelect!.dataSource([], 'ALL-CPU');
301    }
302  };
303
304  cpuSelectMouseUpHandler = (): void => {
305    if (SpRecordTrace.serialNumber === '') {
306      this.cpuSelect?.dataSource([], '');
307    } else {
308      if (this.sp!.search) {
309        this.sp!.search = false;
310        this.recordPerfSearch!.clear();
311      }
312      if (SpRecordTrace.isVscode) {
313        let cmd = Cmd.formatString(CmdConstant.CMD_GET_CPU_COUNT_DEVICES, [SpRecordTrace.serialNumber]);
314        Cmd.execHdcCmd(cmd, (res: string) => {
315          this.cpuData = [];
316          let cpuCount = res!.trim();
317          let cpus = Number(cpuCount);
318          for (let index = 0; index < cpus; index++) {
319            this.cpuData.push(String(index));
320          }
321          this.cpuSelect?.dataSource(this.cpuData, 'ALL-CPU');
322        });
323      } else {
324        HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => {
325          this.cpuData = [];
326          if (conn) {
327            HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_CPU_COUNT, false).then((res) => {
328              let cpuCount = res!.trim();
329              let cpus = Number(cpuCount);
330              for (let index = 0; index < cpus; index++) {
331                this.cpuData.push(String(index));
332              }
333              this.cpuSelect?.dataSource(this.cpuData, 'ALL-CPU');
334            });
335          } else {
336            this.recordPerfSearch!.clear();
337            this.sp!.search = true;
338            this.recordPerfSearch!.setPercent('please kill other hdc-server !', -2);
339          }
340        });
341      }
342    }
343  };
344
345  eventSelectMousedownHandler = (): void => {
346    if (SpRecordTrace.serialNumber === '') {
347      this.eventSelect!.dataSource([], '');
348    }
349  };
350
351  eventSelectClickHandler = (): void => {
352    if (SpRecordTrace.serialNumber === '') {
353      this.eventSelect?.dataSource(eventSelect, '');
354    } else {
355      if (this.sp!.search) {
356        this.sp!.search = false;
357        this.recordPerfSearch!.clear();
358      }
359      if (SpRecordTrace.isVscode) {
360        let cmd = Cmd.formatString(CmdConstant.CMD_GET_HIPERF_EVENTS_DEVICES, [SpRecordTrace.serialNumber]);
361        Cmd.execHdcCmd(cmd, (res: string) => {
362          let eventMap = this.parseEvent(res);
363          let eventList = this.getSoftHardWareEvents(eventMap);
364          if (eventList) {
365            for (let eventListElement of eventList) {
366              this.eventData.push(eventListElement.trim());
367            }
368          }
369          this.eventSelect!.dataSource(this.eventData, '');
370        });
371      } else {
372        HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => {
373          this.eventData = [];
374          if (conn) {
375            HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_HIPERF_EVENTS, false).then((res) => {
376              if (res) {
377                let eventMap = this.parseEvent(res);
378                let eventList = this.getSoftHardWareEvents(eventMap);
379                if (eventList) {
380                  for (let eventListElement of eventList) {
381                    this.eventData.push(eventListElement.trim());
382                  }
383                }
384                this.eventSelect!.dataSource(this.eventData, '');
385              }
386            });
387          } else {
388            this.sp!.search = true;
389            this.recordPerfSearch!.clear();
390            this.recordPerfSearch!.setPercent('please kill other hdc-server !', -2);
391          }
392        });
393      }
394    }
395  };
396
397  initElements(): void {
398    this.cpuData = [];
399    this.eventData = [];
400    this.initRecordPerfConfig();
401    this.sp = document.querySelector('sp-application') as SpApplication;
402    this.recordPerfSearch = this.sp?.shadowRoot?.querySelector('#lit-record-search') as LitSearch;
403    this.processSelect = this.shadowRoot?.querySelector<LitSelectV>("lit-select-v[title='Process']");
404    this.recordProcessInput = this.processSelect?.shadowRoot?.querySelector<HTMLInputElement>('input');
405    this.processInput = this.processSelect!.shadowRoot?.querySelector('input') as HTMLInputElement;
406    this.cpuSelect = this.shadowRoot?.querySelector<LitSelectV>("lit-select-v[title='CPU']");
407    this.inputCpu = this.cpuSelect!.shadowRoot?.querySelector('input') as HTMLInputElement;
408    this.eventSelect = this.shadowRoot?.querySelector<LitSelectV>("lit-select-v[title='Event List']");
409    this.inputEvent = this.eventSelect!.shadowRoot?.querySelector('input') as HTMLInputElement;
410    this.frequencySetInput = this.shadowRoot?.querySelector<HTMLInputElement>("input[title='Frequency']");
411    this.frequencySetInput!.onkeydown = (ev): void => {
412      // @ts-ignore
413      if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
414        ev.preventDefault();
415      }
416    };
417    this.offCPUSwitch = this.shadowRoot?.querySelector<LitSwitch>("lit-switch[title='Off CPU']");
418    this.kernelChainSwitch = this.shadowRoot?.querySelector<LitSwitch>("lit-switch[title='Kernel Chain']");
419    this.callSelect = this.shadowRoot?.querySelector<LitSelect>("lit-select[title='Call Stack']");
420    this.addOptionButton!.addEventListener('click', () => {
421      if (!this.startSamp) {
422        return;
423      }
424      this.addOptionButton!.style.display = 'none';
425      this.show = true;
426    });
427    this.disable();
428  }
429
430  private configTypeBySwitch(config: unknown, recordPerfHeadDiv: HTMLDivElement): void {
431    let recordPerfSwitch = document.createElement('lit-switch') as LitSwitch;
432    recordPerfSwitch.className = 'config';
433    //@ts-ignore
434    recordPerfSwitch.title = config.title;
435    //@ts-ignore
436    recordPerfSwitch.checked = !!config.value;
437    //@ts-ignore
438    if (config.title === 'Start Hiperf Sampling') {
439      recordPerfSwitch.addEventListener('change', (event: CustomEventInit<LitSwitchChangeEvent>) => {
440        let detail = event.detail;
441        if (detail!.checked) {
442          this.startSamp = true;
443          this.unDisable();
444          this.dispatchEvent(new CustomEvent('addProbe', {}));
445        } else {
446          this.startSamp = false;
447          this.addOptionButton!.style.display = 'unset';
448          this.disable();
449          this.show = false;
450        }
451      });
452    }
453    recordPerfHeadDiv.appendChild(recordPerfSwitch);
454  }
455
456  private configTypeBySelect(config: unknown, recordPerfDiv: HTMLDivElement): void {
457    let recordPerfSelect = '';
458    recordPerfSelect += `<lit-select rounded="" default-value="" class="record-perf-select config" 
459placement="bottom" title="${
460      //@ts-ignore
461      config.title
462    }"  placeholder="${
463      //@ts-ignore
464      config.selectArray[0]
465    }">`;
466    //@ts-ignore
467    config.selectArray.forEach((value: string) => {
468      recordPerfSelect += `<lit-select-option value="${value}">${value}</lit-select-option>`;
469    });
470    recordPerfSelect += '</lit-select>';
471    recordPerfDiv.innerHTML = recordPerfDiv.innerHTML + recordPerfSelect;
472  }
473
474  private configTypeByInput(config: unknown, recordPerfDiv: HTMLDivElement): void {
475    let recordPerfInput = document.createElement('input');
476    recordPerfInput.className = 'record-perf-input config';
477    //@ts-ignore
478    recordPerfInput.textContent = config.value;
479    //@ts-ignore
480    recordPerfInput.value = config.value;
481    //@ts-ignore
482    recordPerfInput.title = config.title;
483    recordPerfInput.oninput = (): void => {
484      recordPerfInput.value = recordPerfInput.value.replace(/\D/g, '');
485    };
486    recordPerfDiv.appendChild(recordPerfInput);
487  }
488
489  private configTypeByMmapLitSlider(config: unknown, recordPerfDiv: HTMLDivElement): void {
490    //@ts-ignore
491    let defaultValue = Math.pow(2, config.litSliderStyle.defaultValue);
492    let mapsilder = `
493<div class="sliderBody"><lit-slider defaultColor="var(--dark-color3,#46B1E3)" open dir="right" 
494class="silderclass config" title="${
495      //@ts-ignore
496      config.title
497    }"></lit-slider><input readonly class="sliderInput" 
498type="text" value = '    ${defaultValue} ${
499      //@ts-ignore
500      config.litSliderStyle.resultUnit
501    }' ></div>`;
502    recordPerfDiv.innerHTML = recordPerfDiv.innerHTML + mapsilder;
503    let maplitSlider = recordPerfDiv.querySelector<LitSlider>('.silderclass');
504    //@ts-ignore
505    maplitSlider!.percent = config.litSliderStyle.defaultValue;
506    let mapsliderBody = recordPerfDiv.querySelector<HTMLDivElement>('.sliderBody');
507    let mapbufferInput = recordPerfDiv?.querySelector('.sliderInput') as HTMLInputElement;
508    maplitSlider!.addEventListener('input', () => {
509      let percnet = mapsliderBody!.getAttribute('percent');
510      if (percnet !== null) {
511        //@ts-ignore
512        mapbufferInput.value = Math.pow(2, Number(percnet)) + config.litSliderStyle.resultUnit;
513      }
514    });
515    //@ts-ignore
516    maplitSlider!.sliderStyle = config.litSliderStyle;
517  }
518
519  private configTypeByLitSlider(config: unknown, recordPerfDiv: HTMLDivElement): void {
520    let sliderEl = `
521<div class="sliderBody"><lit-slider defaultColor="var(--dark-color3,#46B1E3)" open dir="right" 
522class="silderclass config" title="${
523      //@ts-ignore
524      config.title
525    }"></lit-slider><input readonly class="sliderInput" 
526type="text" value = '    ${
527      //@ts-ignore
528      config.litSliderStyle.defaultValue
529    } ${
530      //@ts-ignore
531      config.litSliderStyle.resultUnit
532    }' >
533</div>`;
534    recordPerfDiv.innerHTML = recordPerfDiv.innerHTML + sliderEl;
535    let litSlider = recordPerfDiv.querySelector<LitSlider>('.silderclass');
536    //@ts-ignore
537    litSlider!.percent = config.litSliderStyle.defaultValue;
538    let sliderBody = recordPerfDiv.querySelector<HTMLDivElement>('.sliderBody');
539    let bufferInput = recordPerfDiv?.querySelector('.sliderInput') as HTMLInputElement;
540    litSlider!.addEventListener('input', () => {
541      //@ts-ignore
542      bufferInput.value = sliderBody!.getAttribute('percent') + config.litSliderStyle.resultUnit;
543    });
544    //@ts-ignore
545    litSlider!.sliderStyle = config.litSliderStyle;
546  }
547
548  private configTypeBySelectMultiple(config: unknown, recordPerfDiv: HTMLDivElement): void {
549    let html = '';
550    //@ts-ignore
551    let placeholder = config.selectArray[0];
552    //@ts-ignore
553    if (config.title === 'Event List') {
554      placeholder = 'NONE';
555    }
556    html += `<lit-select-v default-value="" rounded="" class="record-perf-select config" 
557mode="multiple" canInsert="" title="${
558      //@ts-ignore
559      config.title
560    }" rounded placement = "bottom" placeholder="${placeholder}">`;
561    //@ts-ignore
562    config.selectArray.forEach((value: string) => {
563      html += `<lit-select-option value="${value}">${value}</lit-select-option>`;
564    });
565    html += '</lit-select-v>';
566    recordPerfDiv.innerHTML = recordPerfDiv.innerHTML + html;
567  }
568
569  getSoftHardWareEvents(eventListResult: Map<string, string[]>): string[] {
570    let shEvents = [];
571    let hardwareEvents = eventListResult.get('hardware');
572    if (hardwareEvents) {
573      for (let hardwareEvent of hardwareEvents) {
574        shEvents.push(hardwareEvent);
575      }
576    }
577    let softwareEvents = eventListResult.get('software');
578    if (softwareEvents) {
579      for (let softwareEvent of softwareEvents) {
580        shEvents.push(softwareEvent);
581      }
582    }
583    return shEvents;
584  }
585
586  parseEvent(eventListResult: string): Map<string, Array<string>> {
587    let eventMap: Map<string, Array<string>> = new Map<string, Array<string>>();
588    let events: Array<string> = [];
589    let type: string = '';
590    let lineValues: string[] = eventListResult.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/);
591    for (let line of lineValues) {
592      if (line.startsWith('Supported')) {
593        let startSign: string = 'for';
594        type = line.substring(line.indexOf(startSign) + startSign.length, line.lastIndexOf(':')).trim();
595        events = [];
596        eventMap.set(type, events);
597      } else if (
598        line.indexOf('not support') !== -1 ||
599        line.trim().length === 0 ||
600        line.indexOf('Text file busy') !== -1
601      ) {
602        // do not need deal with it
603      } else {
604        let event: string = line.split(' ')[0];
605        let ventMap = eventMap.get(type);
606        if (ventMap !== null) {
607          ventMap!.push(event);
608        }
609      }
610    }
611    return eventMap;
612  }
613
614  private unDisable(): void {
615    if (this.processSelect) {
616      this.processSelect.removeAttribute('disabled');
617    }
618    if (this.frequencySetInput) {
619      this.frequencySetInput!.disabled = false;
620    }
621    if (this.offCPUSwitch) {
622      this.offCPUSwitch!.disabled = false;
623    }
624    if (this.kernelChainSwitch) {
625      this.kernelChainSwitch!.disabled = false;
626    }
627    if (this.callSelect) {
628      this.callSelect!.removeAttribute('disabled');
629    }
630    if (this.addOptionButton) {
631      this.addOptionButton.disabled = false;
632    }
633  }
634
635  private disable(): void {
636    if (this.processSelect) {
637      this.processSelect.setAttribute('disabled', '');
638    }
639    if (this.frequencySetInput) {
640      this.frequencySetInput!.disabled = true;
641    }
642    if (this.offCPUSwitch) {
643      this.offCPUSwitch!.disabled = true;
644    }
645    if (this.kernelChainSwitch) {
646      this.kernelChainSwitch!.disabled = true;
647    }
648    if (this.callSelect) {
649      this.callSelect!.setAttribute('disabled', '');
650    }
651    if (this.addOptionButton) {
652      this.addOptionButton.disabled = true;
653    }
654  }
655
656  connectedCallback(): void {
657    let traceMode = this.shadowRoot!.querySelector('#traceMode') as HTMLDivElement;
658    let isLongTrace = SpApplication.isLongTrace;
659    if (isLongTrace) {
660      traceMode!.style.display = 'block';
661    } else {
662      traceMode!.style.display = 'none';
663    }
664    this.processInput?.addEventListener('mousedown', this.processSelectMousedownHandler);
665    this.inputCpu?.addEventListener('mousedown', this.cpuSelectMouseDownHandler);
666    this.inputCpu?.addEventListener('mouseup', this.cpuSelectMouseUpHandler);
667    this.inputEvent?.addEventListener('mousedown', this.eventSelectMousedownHandler);
668    this.inputEvent?.addEventListener('click', this.eventSelectClickHandler);
669  }
670
671  disconnectedCallback(): void {
672    super.disconnectedCallback();
673    this.processInput?.removeEventListener('mousedown', this.processSelectMousedownHandler);
674    this.inputCpu?.removeEventListener('mousedown', this.cpuSelectMouseDownHandler);
675    this.inputCpu?.removeEventListener('mouseup', this.cpuSelectMouseUpHandler);
676    this.inputEvent?.removeEventListener('mousedown', this.eventSelectMousedownHandler);
677    this.inputEvent?.removeEventListener('click', this.eventSelectClickHandler);
678  }
679
680  initHtml(): string {
681    return SpRecordPerfHtml;
682  }
683}
684
685export interface PerfConfig {
686  process: string;
687  cpu: string;
688  eventList: string;
689  cpuPercent: number;
690  frequency: number;
691  period: number;
692  isOffCpu: boolean;
693  noInherit: boolean;
694  callStack: string;
695  branch: string;
696  mmap: number;
697  clockType: string;
698  isKernelChain: boolean;
699}
700
701const eventSelect = [
702  'hw-cpu-cycles',
703  'hw-instructions',
704  'hw-cache-references',
705  'hw-cache-misses',
706  'hw-branch-instructions',
707  'hw-branch-misses',
708  'hw-bus-cycles',
709  'hw-stalled-cycles-backend',
710  'hw-stalled-cycles-frontend',
711  'sw-cpu-clock',
712  'sw-task-clock',
713  'sw-page-faults',
714  'sw-context-switches',
715  'sw-cpu-migrations',
716  'sw-page-faults-min',
717  'sw-page-faults-maj',
718  'sw-alignment-faults',
719  'sw-emulation-faults',
720  'sw-dummy',
721  'sw-bpf-output',
722];
723
724const perfConfigList = [
725  {
726    title: 'Start Hiperf Sampling',
727    des: '',
728    hidden: false,
729    type: 'switch',
730    value: false,
731  },
732  {
733    type: 'select-multiple',
734    title: 'Process',
735    des: 'Record process',
736    hidden: false,
737    selectArray: [''],
738  },
739  {
740    title: 'CPU',
741    des: 'Record assign cpu num such as 0,1,2',
742    hidden: true,
743    type: 'select-multiple',
744    selectArray: [''],
745  },
746  {
747    title: 'Event List',
748    des: 'Event type Default is cpu cycles',
749    hidden: true,
750    type: 'select-multiple',
751    selectArray: [''],
752  },
753  {
754    title: 'CPU Percent',
755    des: 'Set the max percent of cpu time used for recording',
756    hidden: true,
757    type: 'lit-slider',
758    litSliderStyle: {
759      minRange: 0,
760      maxRange: 100,
761      defaultValue: '100',
762      resultUnit: '%',
763      stepSize: 1,
764      lineColor: 'var(--dark-color3,#a88888)',
765      buttonColor: '#a88888',
766    },
767  },
768  {
769    title: 'Frequency',
770    des: 'Set event sampling frequency',
771    hidden: false,
772    type: 'input',
773    value: '1000',
774  },
775  {
776    title: 'Period',
777    des: 'Set event sampling period for trace point events2',
778    hidden: true,
779    type: 'input',
780    value: '1',
781  },
782  {
783    title: 'Off CPU',
784    des: 'Trace when threads are scheduled off cpu',
785    hidden: false,
786    type: 'switch',
787    value: false,
788  },
789  {
790    title: 'Kernel Chain',
791    des: '',
792    hidden: false,
793    type: 'switch',
794    value: false,
795  },
796  {
797    title: 'No Inherit',
798    des: "Don't trace child processes",
799    hidden: true,
800    type: 'switch',
801    value: false,
802  },
803  {
804    title: 'Call Stack',
805    des: 'Setup and enable call stack recording',
806    hidden: false,
807    type: 'select',
808    selectArray: ['dwarf', 'fp', 'none'],
809  },
810  {
811    title: 'Branch',
812    des: 'Taken branch stack sampling',
813    hidden: true,
814    type: 'select',
815    selectArray: ['none', 'any', 'any_call', 'any_ret', 'ind_call', 'call', 'user', 'kernel'],
816  },
817  {
818    title: 'Mmap Pages',
819    des: 'Used to receiving record data from kernel',
820    hidden: true,
821    type: 'Mmap-lit-slider',
822    litSliderStyle: {
823      minRange: 1,
824      maxRange: 10,
825      defaultValue: '8',
826      resultUnit: 'MB',
827      stepSize: 1,
828      lineColor: 'var(--dark-color3,#46B1E3)',
829      buttonColor: '#999999',
830    },
831  },
832  {
833    title: 'Clock Type',
834    des: 'Set the clock id to use for the various time fields in the perf_event_type records',
835    hidden: true,
836    type: 'select',
837    selectArray: ['monotonic', 'realtime', 'monotonic_raw', 'boottime', 'perf'],
838  },
839];
840