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.js'; 17import '../../../base-ui/select/LitAllocationSelect.js'; 18 19import '../../../base-ui/switch/lit-switch.js'; 20import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; 21import { SpRecordTrace } from '../SpRecordTrace.js'; 22import { Cmd } from '../../../command/Cmd.js'; 23import { LitRadioBox } from '../../../base-ui/radiobox/LitRadioBox.js'; 24import { SpCheckDesBox } from './SpCheckDesBox.js'; 25import LitSwitch from '../../../base-ui/switch/lit-switch.js'; 26 27@element('sp-ark-ts') 28export class SpArkTs extends BaseElement { 29 private processInput: LitAllocationSelect | undefined | null; 30 private spCheckDesBox: SpCheckDesBox | undefined | null; 31 private radioBox: LitRadioBox | undefined | null; 32 private interval: HTMLInputElement | undefined | null; 33 private memorySwitch: LitSwitch | undefined | null; 34 private cpuSwitch: LitSwitch | undefined | null; 35 36 set startSamp(jsHeapStart: boolean) { 37 if (jsHeapStart) { 38 this.setAttribute('startSamp', ''); 39 } else { 40 this.removeAttribute('startSamp'); 41 } 42 } 43 44 get startSamp(): boolean { 45 return this.hasAttribute('startSamp'); 46 } 47 48 get process(): string { 49 if (this.processInput!.value.length > 0) { 50 return this.processInput!.value; 51 } 52 return ''; 53 } 54 55 get radioBoxType(): number { 56 let memorySwitch = this.shadowRoot?.querySelector('#memory-switch'); 57 let type: string; 58 if (memorySwitch!.getAttribute('checked') !== null) { 59 this.radioBox = this.shadowRoot?.querySelector(`lit-radio[checked]`); 60 type = this.radioBox?.getAttribute('type') || ''; 61 } else { 62 type = '-1'; 63 } 64 return Number(type); 65 } 66 67 get grabNumeric(): boolean { 68 if (this.radioBoxType === 0) { 69 this.spCheckDesBox = this.shadowRoot?.querySelector('#snapshot'); 70 let isChecked = this.spCheckDesBox?.getAttribute('checked'); 71 return isChecked === 'true'; 72 } else { 73 return false; 74 } 75 } 76 77 get grabAllocations(): boolean { 78 if (this.radioBoxType === 1) { 79 this.spCheckDesBox = this.shadowRoot?.querySelector('#timeline'); 80 let isChecked = this.spCheckDesBox?.getAttribute('checked'); 81 return isChecked === 'true'; 82 } else { 83 return false; 84 } 85 } 86 87 get intervalValue(): number { 88 if (this.radioBoxType === 0) { 89 return Number(this.interval!.value); 90 } else { 91 return 0; 92 } 93 } 94 95 get grabCpuProfiler(): boolean { 96 let isChecked = this.cpuSwitch?.getAttribute('checked'); 97 return isChecked !== null; 98 } 99 100 get intervalCpuValue(): number { 101 let interval = this.shadowRoot?.querySelector<HTMLInputElement>('#cpuInterval'); 102 if (interval) { 103 return Number(interval!.value); 104 } else { 105 return 0; 106 } 107 } 108 109 initElements(): void { 110 this.interval = this.shadowRoot?.querySelector('#interval'); 111 this.processInput = this.shadowRoot?.querySelector<LitAllocationSelect>('lit-allocation-select'); 112 let processInput = this.processInput?.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; 113 this.cpuSwitch = this.shadowRoot?.querySelector('#cpu-switch') as LitSwitch; 114 processInput!.addEventListener('mousedown', (ev) => { 115 if (SpRecordTrace.serialNumber == '') { 116 this.processInput!.processData = []; 117 this.processInput!.initData(); 118 } 119 }); 120 processInput!.addEventListener('mouseup', () => { 121 if (SpRecordTrace.serialNumber == '') { 122 this.processInput!.processData = []; 123 this.processInput!.initData(); 124 } else { 125 Cmd.getDebugProcess().then((processList) => { 126 this.processInput!.processData = processList; 127 this.processInput!.initData(); 128 }); 129 } 130 }); 131 this.interval!.addEventListener('focusout', () => { 132 if (this.interval!.value === '') { 133 this.interval!.value = '10'; 134 } 135 }); 136 137 let litSwitch = this.shadowRoot?.querySelector('lit-switch') as LitSwitch; 138 litSwitch.addEventListener('change', (event: any) => { 139 let detail = event.detail; 140 if (detail.checked) { 141 this.unDisable(); 142 this.unMemoryDisable(); 143 } else { 144 this.disable(); 145 this.memoryDisable(); 146 } 147 }); 148 this.memorySwitch = this.shadowRoot?.querySelector('#memory-switch') as LitSwitch; 149 this.memorySwitch.addEventListener('change', (event: any) => { 150 let detail = event.detail; 151 if (detail.checked) { 152 this.unMemoryDisable(); 153 } else { 154 if (!this.cpuSwitch?.checked) { 155 litSwitch.checked = false; 156 this.disable(); 157 } 158 this.memoryDisable(); 159 } 160 }); 161 162 this.cpuSwitch = this.shadowRoot?.querySelector('#cpu-switch') as LitSwitch; 163 this.cpuSwitch.addEventListener('change', (event: any) => { 164 let detail = event.detail; 165 let interval = this.shadowRoot?.querySelectorAll<HTMLInputElement>('#cpuInterval'); 166 if (!detail.checked && !this.memorySwitch?.checked) { 167 litSwitch.checked = false; 168 this.disable(); 169 } else if (detail.checked) { 170 interval!.forEach((item) => { 171 item.disabled = false; 172 item.style.background = 'var(--dark-background5,#FFFFFF)'; 173 }); 174 } else { 175 interval!.forEach((item) => { 176 item.disabled = true; 177 item.style.color = '#b7b7b7'; 178 item.style.background = 'var(--dark-background1,#f5f5f5)'; 179 }); 180 litSwitch.checked = true; 181 this.startSamp = true; 182 } 183 }); 184 this.disable(); 185 this.memoryDisable(); 186 } 187 188 private memoryDisable() { 189 let interval = this.shadowRoot?.querySelectorAll<HTMLInputElement>('#interval'); 190 interval!.forEach((item) => { 191 item.disabled = true; 192 item.style.color = '#b7b7b7'; 193 item.style.background = 'var(--dark-background1,#f5f5f5)'; 194 }); 195 let radioBoxes = this.shadowRoot?.querySelectorAll<LitRadioBox>('lit-radio'); 196 radioBoxes!.forEach((item) => { 197 item.disabled = true; 198 }); 199 let checkBoxes = this.shadowRoot?.querySelectorAll<SpCheckDesBox>('check-des-box'); 200 checkBoxes!.forEach((item) => { 201 item.disabled = true; 202 }); 203 } 204 205 private unMemoryDisable() { 206 let interval = this.shadowRoot?.querySelectorAll<HTMLInputElement>('#interval'); 207 interval!.forEach((item) => { 208 item.disabled = false; 209 item.style.background = 'var(--dark-background5,#FFFFFF)'; 210 }); 211 let radioBoxes = this.shadowRoot?.querySelectorAll<LitRadioBox>('lit-radio'); 212 radioBoxes!.forEach((item) => { 213 item.disabled = false; 214 }); 215 let checkBoxes = this.shadowRoot?.querySelectorAll<SpCheckDesBox>('check-des-box'); 216 checkBoxes!.forEach((item) => { 217 item.disabled = false; 218 }); 219 } 220 221 private disable() { 222 this.startSamp = false; 223 this.processInput!.setAttribute('disabled', ''); 224 let heapConfigs = this.shadowRoot?.querySelectorAll<HTMLInputElement>('.select'); 225 heapConfigs!.forEach((item) => { 226 item.disabled = true; 227 }); 228 let switches = this.shadowRoot?.querySelectorAll<LitSwitch>('.switch'); 229 switches!.forEach((item) => { 230 item.disabled = true; 231 item.checked = false; 232 }); 233 let interval = this.shadowRoot?.querySelectorAll<HTMLInputElement>('.inputstyle'); 234 interval!.forEach((item) => { 235 item.disabled = true; 236 item.style.color = '#b7b7b7'; 237 item.style.background = 'var(--dark-background1,#f5f5f5)'; 238 }); 239 } 240 241 private unDisable() { 242 this.startSamp = true; 243 this.processInput!.removeAttribute('disabled'); 244 let heapConfigs = this.shadowRoot?.querySelectorAll<HTMLInputElement>('.select'); 245 heapConfigs!.forEach((item) => { 246 item.disabled = false; 247 }); 248 let switches = this.shadowRoot?.querySelectorAll<LitSwitch>('.switch'); 249 switches!.forEach((item) => { 250 item.disabled = false; 251 item.checked = true; 252 }); 253 let interval = this.shadowRoot?.querySelectorAll<HTMLInputElement>('.inputstyle'); 254 interval!.forEach((item) => { 255 item.disabled = false; 256 item.style.background = 'var(--dark-background5,#FFFFFF)'; 257 }); 258 } 259 260 initHtml(): string { 261 return ` 262 <style> 263 :host{ 264 display: inline-block; 265 width: 100%; 266 height: 100%; 267 background: var(--dark-background3,#FFFFFF); 268 border-radius: 0px 16px 16px 0px; 269 } 270 .root { 271 padding-top: 30px; 272 padding-left: 54px; 273 margin-right: 30px; 274 font-size:16px; 275 margin-bottom: 30px; 276 } 277 .config-div { 278 width: 80%; 279 display: flex; 280 flex-direction: column; 281 margin-top: 5vh; 282 margin-bottom: 5vh; 283 gap: 25px; 284 } 285 .title { 286 opacity: 0.9; 287 font-family: Helvetica-Bold; 288 font-size: 18px; 289 text-align: center; 290 line-height: 40px; 291 font-weight: 700; 292 margin-right: 10px; 293 } 294 .config-title{ 295 margin-left: 20px; 296 font-weight: 700; 297 line-height: 48px; 298 } 299 .memory { 300 margin-left: 40px; 301 } 302 .des { 303 color: #242424; 304 font-family: Helvetica; 305 font-size: 14px; 306 text-align: left; 307 line-height: 16px; 308 font-weight: 400; 309 } 310 .select { 311 border-radius: 15px; 312 } 313 input { 314 width: 35%; 315 height: 25px; 316 border:0; 317 outline:none; 318 border-radius: 16px; 319 text-indent:2% 320 } 321 input::-webkit-input-placeholder{ 322 color:var(--bark-prompt,#999999); 323 } 324 .inputstyle{ 325 background: var(--dark-background5,#FFFFFF); 326 border: 1px solid var(--dark-background5,#999999); 327 font-family: Helvetica; 328 font-size: 14px; 329 color: var(--dark-color1,#212121); 330 text-align: left; 331 line-height: 16px; 332 font-weight: 400; 333 } 334 .inputstyle::-webkit-input-placeholder { 335 background: var(--dark-background5,#FFFFFF); 336 } 337 .radio { 338 font-family: Helvetica-Bold; 339 font-size: 16px; 340 color: #000000; 341 line-height: 28px; 342 font-weight: 700; 343 } 344 .unit { 345 font-family: Helvetica; 346 font-size: 14px; 347 color: #000000; 348 line-height: 28px; 349 font-weight: 400; 350 } 351 lit-switch { 352 display:inline; 353 float: right; 354 height: 38px; 355 margin-top: 10px; 356 } 357 :host([startSamp]) .inputBoxes { 358 background: var(--dark-background5,#FFFFFF); 359 } 360 :host(:not([startSamp])) .inputBoxes { 361 color: #b7b7b7; 362 background: var(--dark-background1,#f5f5f5); 363 } 364 </style> 365 <div class="root"> 366 <div class="config-div"> 367 <div> 368 <span class="title">Start Ark Ts Record</span> 369 <lit-switch></lit-switch> 370 </div> 371 </div> 372 <div class="config-div"> 373 <div> 374 <span class="title">Process</span> 375 <span class="des">Record process</span> 376 </div> 377 <lit-allocation-select style="width: 100%;" rounded="" default-value="" class="select inputBoxes" placement="bottom" ></lit-allocation-select> 378 </div> 379 <div class="config-div"> 380 <div> 381 <span class="title">Select profiling type</span> 382 </div> 383 <div> 384 <span class="config-title">Start cpu profiler</span> 385 <lit-switch class="switch" id='cpu-switch'></lit-switch> 386 </div> 387 <div style="margin-left: 40px;"> 388 <span class="des">Interval(Available on recent OpenHarmony 4.0)</span> 389 <div style="margin-top: 12px;"> 390 <input class="inputstyle inputBoxes" id='cpuInterval' type="text" id="interval" placeholder="" onkeyup="this.value=this.value.replace(/\\D/g,'').replace(/^0{1,}/g,'')" value="1000"> 391 <span class="unit">μs</span> 392 </div> 393 </div> 394 <div> 395 <span class="config-title">Start memory profiler</span> 396 <lit-switch class="switch" id='memory-switch'></lit-switch> 397 </div> 398 <div class='memory'> 399 <lit-radio dis="round" class="radio" name="litRadio" checked type="0">Heap snapshot</lit-radio> 400 <div style="margin-left: 10px;"> 401 <span class="des">Heap snapshot profiles show memory distribution among your page’s JavaScript objects and related DOM nodes.</span> 402 <div style="display: flex;margin-bottom: 12px;margin-top: 12px;"> 403 <check-des-box checked="true" value ="lnclude numerical values in capture" id="snapshot"> 404 </check-des-box> 405 </div> 406 <span class="des">Interval(Available on recent OpenHarmony 4.0)</span> 407 <div style="margin-top: 12px;"> 408 <input class="inputstyle inputBoxes" type="text" id="interval" placeholder="" onkeyup="this.value=this.value.replace(/\\D/g,'').replace(/^0{1,}/g,'')" value="10"> 409 <span class="unit">S</span> 410 </div> 411 </div> 412 <lit-radio dis="round" name="litRadio" class="radio" type="1">Allocation insteumentation on timeline</lit-radio> 413 <div style="margin-left: 10px;"> 414 <span class="des">Allocation timelines show insturmented Javascript memory allocations over time. Once profile is recorded you can select a time interval to see objects that werre allocated within it and still alive by the end of recording. Use this profile type to isolate memory leaks.</span> 415 <div style="display: flex;margin-top: 12px;"> 416 <check-des-box value ="record stack traces of allocations(extra performance overhead)" id="timeline"> 417 </check-des-box> 418 </div> 419 </div> 420 </div> 421 </、div> 422 </div> 423 `; 424 } 425} 426