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