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