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 { log } from '../../../log/Log.js'; 18import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; 19import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; 20import '../../../base-ui/select/LitAllocationSelect.js'; 21import { SpApplication } from '../../SpApplication.js'; 22import { LitSearch } from '../trace/search/Search.js'; 23import { SpRecordTrace } from '../SpRecordTrace.js'; 24import { Cmd } from '../../../command/Cmd.js'; 25import { CmdConstant } from '../../../command/CmdConstant.js'; 26import LitSwitch from '../../../base-ui/switch/lit-switch.js'; 27import { LitSlider } from '../../../base-ui/slider/LitSlider'; 28 29@element('sp-allocations') 30export class SpAllocations extends BaseElement { 31 private processId: LitAllocationSelect | null | undefined; 32 private unwindEL: HTMLInputElement | null | undefined; 33 private shareMemory: HTMLInputElement | null | undefined; 34 private shareMemoryUnit: HTMLSelectElement | null | undefined; 35 private filterMemory: HTMLInputElement | null | undefined; 36 private filterMemoryUnit: HTMLSelectElement | null | undefined; 37 private fpUnWind: LitSwitch | null | undefined; 38 39 private recordAccurately: LitSwitch | null | undefined; 40 private offlineSymbol: LitSwitch | null | undefined; 41 private startupMode: LitSwitch | null | undefined; 42 private recordStatisticsResult: HTMLDivElement | null | undefined; 43 44 get appProcess(): string { 45 return this.processId!.value || ''; 46 } 47 48 get unwind(): number { 49 log('unwind value is :' + this.unwindEL!.value); 50 return Number(this.unwindEL!.value); 51 } 52 53 get shared(): number { 54 let value = this.shareMemory?.value || ''; 55 log('shareMemory value is :' + value); 56 if (value != '') { 57 let unit = Number(this.shareMemory?.value) || 16384; 58 return unit; 59 } 60 return 16384; 61 } 62 63 get filter(): number { 64 let value = this.filterMemory?.value || ''; 65 log('filter value is :' + value); 66 if (value != '') { 67 return Number(value); 68 } 69 return 4096; 70 } 71 72 get fp_unwind(): boolean { 73 let value = this.fpUnWind?.checked; 74 if (value != undefined) { 75 return value; 76 } 77 return true; 78 } 79 80 get record_accurately(): boolean { 81 let value = this.recordAccurately?.checked; 82 if (value != undefined) { 83 return value; 84 } 85 return true; 86 } 87 88 get offline_symbolization(): boolean { 89 let value = this.offlineSymbol?.checked; 90 if (value != undefined) { 91 return value; 92 } 93 return true; 94 } 95 96 get record_statistics(): boolean { 97 if (this.recordStatisticsResult?.hasAttribute('percent')) { 98 let value = Number(this.recordStatisticsResult?.getAttribute('percent')); 99 return value > 0; 100 } 101 return true; 102 } 103 104 get statistics_interval(): number { 105 if (this.recordStatisticsResult?.hasAttribute('percentValue')) { 106 return Number(this.recordStatisticsResult?.getAttribute('percentValue')); 107 } 108 return 3600; 109 } 110 111 get startup_mode(): boolean { 112 let value = this.startupMode?.checked; 113 if (value != undefined) { 114 return value; 115 } 116 return false; 117 } 118 119 initElements(): void { 120 this.processId = this.shadowRoot?.getElementById('pid') as LitAllocationSelect; 121 let input = this.processId.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; 122 let sp = document.querySelector('sp-application') as SpApplication; 123 let litSearch = sp?.shadowRoot?.querySelector('#lit-record-search') as LitSearch; 124 let allocationProcessData: Array<string> = []; 125 input.addEventListener('mousedown', (ev) => { 126 if (SpRecordTrace.serialNumber == '') { 127 this.processId!.processData = []; 128 } 129 }); 130 input.addEventListener('valuable', (ev) => { 131 this.dispatchEvent(new CustomEvent('addProbe', {})); 132 }); 133 input.addEventListener('inputClick', () => { 134 allocationProcessData = []; 135 if (SpRecordTrace.serialNumber != '') { 136 Cmd.getProcess().then((processList) => { 137 this.processId!.processData = processList; 138 this.processId!.initData(); 139 }); 140 } 141 }); 142 this.unwindEL = this.shadowRoot?.getElementById('unwind') as HTMLInputElement; 143 this.shareMemory = this.shadowRoot?.getElementById('shareMemory') as HTMLInputElement; 144 this.shareMemoryUnit = this.shadowRoot?.getElementById('shareMemoryUnit') as HTMLSelectElement; 145 this.filterMemory = this.shadowRoot?.getElementById('filterSized') as HTMLInputElement; 146 this.filterMemoryUnit = this.shadowRoot?.getElementById('filterSizedUnit') as HTMLSelectElement; 147 this.fpUnWind = this.shadowRoot?.getElementById('use_fp_unwind') as LitSwitch; 148 this.recordAccurately = this.shadowRoot?.getElementById('use_record_accurately') as LitSwitch; 149 this.offlineSymbol = this.shadowRoot?.getElementById('use_offline_symbolization') as LitSwitch; 150 this.startupMode = this.shadowRoot?.getElementById('use_startup_mode') as LitSwitch; 151 let stepValue = [0, 1, 10, 30, 60, 300, 600, 1800, 3600]; 152 let statisticsSlider = this.shadowRoot?.querySelector<LitSlider>('#interval-slider') as LitSlider; 153 154 this.recordStatisticsResult = this.shadowRoot?.querySelector<HTMLDivElement>( 155 '.record-statistics-result' 156 ) as HTMLDivElement; 157 statisticsSlider.sliderStyle = { 158 minRange: 0, 159 maxRange: 3600, 160 defaultValue: '3600', 161 resultUnit: 'S', 162 stepSize: 450, 163 lineColor: 'var(--dark-color3,#46B1E3)', 164 buttonColor: '#999999', 165 }; 166 let parentElement = statisticsSlider!.parentNode as Element; 167 let intervalResultInput = this.shadowRoot?.querySelector('.interval-result') as HTMLInputElement; 168 intervalResultInput.value = statisticsSlider.sliderStyle.defaultValue; 169 statisticsSlider.addEventListener('input', (evt) => { 170 statisticsSlider!.sliderStyle = { 171 minRange: 0, 172 maxRange: 3600, 173 defaultValue: this.recordStatisticsResult!.getAttribute('percent') + '', 174 resultUnit: 'S', 175 stepSize: 450, 176 lineColor: 'var(--dark-color3,#46B1E3)', 177 buttonColor: '#999999', 178 }; 179 intervalResultInput.style.color = 'var(--dark-color1,#000000)'; 180 if (this.recordStatisticsResult!.hasAttribute('percent')) { 181 let step = Number(this.recordStatisticsResult!.getAttribute('percent')) / 450; 182 this.recordStatisticsResult!.setAttribute('percentValue', stepValue[step] + ''); 183 intervalResultInput.value = stepValue[step] + ''; 184 } 185 }); 186 parentElement.setAttribute('percent', '3600'); 187 intervalResultInput.style.color = 'var(--dark-color1,#000000)'; 188 intervalResultInput.addEventListener('input', (ev) => { 189 if (this.recordStatisticsResult!.hasAttribute('percent')) { 190 this.recordStatisticsResult!.removeAttribute('percent'); 191 } 192 intervalResultInput.style.color = 'var(--dark-color1,#000000)'; 193 intervalResultInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; 194 intervalResultInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; 195 if (intervalResultInput.value.trim() == '') { 196 intervalResultInput.style.color = 'red'; 197 parentElement.setAttribute('percent', '3600'); 198 return; 199 } 200 let memorySize = Number(intervalResultInput.value); 201 if (memorySize < statisticsSlider!.sliderStyle.minRange || memorySize > statisticsSlider!.sliderStyle.maxRange) { 202 intervalResultInput.style.color = 'red'; 203 parentElement.setAttribute('percent', '3600'); 204 } else { 205 statisticsSlider!.percent = intervalResultInput.value; 206 let htmlInputElement = statisticsSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; 207 htmlInputElement.value = intervalResultInput.value; 208 statisticsSlider!.sliderStyle = { 209 minRange: 0, 210 maxRange: 3600, 211 defaultValue: intervalResultInput.value, 212 resultUnit: 'S', 213 stepSize: 1, 214 lineColor: 'var(--dark-color3,#46B1E3)', 215 buttonColor: '#999999', 216 }; 217 parentElement.setAttribute('percent', intervalResultInput.value); 218 parentElement.setAttribute('percentValue', intervalResultInput.value); 219 } 220 }); 221 222 intervalResultInput.addEventListener('focusout', (ev) => { 223 if (intervalResultInput.value.trim() == '') { 224 parentElement.setAttribute('percent', '3600'); 225 intervalResultInput.value = '3600'; 226 intervalResultInput.style.color = 'var(--dark-color,#6a6f77)'; 227 parentElement.setAttribute('percent', intervalResultInput.value); 228 parentElement.setAttribute('percentValue', intervalResultInput.value); 229 statisticsSlider!.percent = intervalResultInput.value; 230 let htmlInputElement = statisticsSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; 231 htmlInputElement.value = intervalResultInput.value; 232 } 233 }); 234 statisticsSlider.shadowRoot?.querySelector<HTMLElement>('#slider')!.addEventListener('mouseup', (ev) => { 235 setTimeout(() => { 236 let percentValue = this.recordStatisticsResult!.getAttribute('percent'); 237 let index = Number(percentValue) / 450; 238 index = index < 1 ? 0 : index; 239 intervalResultInput.value = stepValue[index] + ''; 240 this.recordStatisticsResult!.setAttribute('percentValue', stepValue[index] + ''); 241 }); 242 }); 243 } 244 245 initHtml(): string { 246 return ` 247 <style> 248 :host{ 249 display: block; 250 width: 100%; 251 border-radius: 0px 16px 16px 0px; 252 height: 100%; 253 } 254 .title { 255 grid-column: span 2 / auto; 256 } 257 .allocation-font-style{ 258 font-family: Helvetica-Bold; 259 font-size: 1em; 260 color: var(--dark-color1,#000000); 261 line-height: 28px; 262 font-weight: 700; 263 } 264 .root { 265 padding-top: 45px; 266 margin-left: 40px; 267 display: grid; 268 grid-template-columns: repeat(2, 1fr); 269 grid-template-rows: min-content 1fr min-content; 270 width: 90%; 271 border-radius: 0px 16px 16px 0px; 272 } 273 .allocation-inner-font-style { 274 font-family: Helvetica,serif; 275 font-size: 1em; 276 color: var(--dark-color1,#000000); 277 text-align: left; 278 line-height: 20px; 279 font-weight: 400; 280 display:flex; 281 width:75%; 282 margin-top: 3px; 283 284 } 285 input { 286 width: 72%; 287 height: 25px; 288 border:0; 289 outline:none; 290 border-radius: 16px; 291 text-indent:2% 292 } 293 input::-webkit-input-placeholder{ 294 color:var(--bark-prompt,#999999); 295 } 296 .allocation-select { 297 height: 30px; 298 border:0; 299 border-radius: 3px; 300 outline:none; 301 border: 1px solid var(--dark-border,#B3B3B3); 302 width: 60px; 303 background-color:var(--dark-background5, #FFFFFF) 304 font-family: Helvetica; 305 font-size: 14px; 306 color:var(--dark-color,#212121) 307 text-align: center; 308 line-height: 16px; 309 font-weight: 400; 310 border-radius: 16px; 311 } 312 .allocation-application{ 313 display: flex; 314 flex-direction: column; 315 grid-gap: 15px; 316 margin-top: 40px; 317 } 318 .allocation-switchstyle{ 319 margin-top: 40px; 320 display: flex; 321 } 322 .allocation-inputstyle{ 323 background: var(--dark-background5,#FFFFFF); 324 border: 1px solid var(--dark-background5,#999999); 325 font-family: Helvetica; 326 font-size: 14px; 327 color: var(--dark-color1,#212121); 328 text-align: left; 329 line-height: 16px; 330 font-weight: 400; 331 } 332 .allocation-inputstyle::-webkit-input-placeholder { 333 background: var(--dark-background5,#FFFFFF); 334 } 335 #one_mb{ 336 background-color:var(--dark-background5, #FFFFFF) 337 } 338 #one_kb{ 339 background-color:var(--dark-background5, #FFFFFF) 340 } 341 #two_mb{ 342 background-color:var(--dark-background5, #FFFFFF) 343 } 344 #two_kb{ 345 background-color:var(--dark-background5, #FFFFFF) 346 } 347 .processSelect { 348 border-radius: 15px; 349 width: 84%; 350 } 351 .value-range { 352 opacity: 0.6; 353 font-family: Helvetica; 354 font-size: 1em; 355 color: var(--dark-color,#000000); 356 text-align: left; 357 line-height: 20px; 358 font-weight: 400; 359 } 360 .record-title{ 361 margin-bottom: 16px; 362 grid-column: span 3; 363 } 364 #interval-slider { 365 margin: 0 8px; 366 grid-column: span 2; 367 } 368 .resultSize{ 369 display: grid; 370 grid-template-rows: 1fr; 371 grid-template-columns: min-content min-content; 372 background-color: var(--dark-background5,#F2F2F2); 373 -webkit-appearance:none; 374 color:var(--dark-color,#6a6f77); 375 width: 150px; 376 margin: 0 30px 0 0; 377 height: 40px; 378 border-radius:20px; 379 outline:0; 380 border:1px solid var(--dark-border,#c8cccf); 381 } 382 .record-mode{ 383 font-family: Helvetica-Bold; 384 font-size: 1em; 385 color: var(--dark-color1,#000000); 386 line-height: 28px; 387 font-weight: 400; 388 margin-bottom: 16px; 389 grid-column: span 1; 390 } 391 .allocation-record-prompt{ 392 opacity: 0.6; 393 font-family: Helvetica; 394 font-size: 14px; 395 text-align: center; 396 line-height: 35px; 397 font-weight: 400; 398 } 399 .interval-result{ 400 -webkit-appearance:none; 401 border: none; 402 text-align: center; 403 width: 90px; 404 font-size:14px; 405 outline:0; 406 margin: 5px 0 5px 5px; 407 background-color: var(--dark-background5,#F2F2F2); 408 color:var(--dark-color,#6a6f77); 409 } 410 411 </style> 412 <div class="root"> 413 <div class = "title"> 414 <span class="allocation-font-style">Native Memory</span> 415 </div> 416 <div class="allocation-application"> 417 <span class="allocation-inner-font-style">ProcessId or ProcessName</span> 418 <span class="value-range">Record process</span> 419 <lit-allocation-select show-search class="processSelect" rounded default-value="" id="pid" placement="bottom" title="process" placeholder="please select process"> 420 </lit-allocation-select> 421 </div> 422 <div class="allocation-application"> 423 <span class="allocation-inner-font-style" >Max unwind level</span> 424 <span class="value-range">Max Unwind Level Rang is 0 - 512, default 10</span> 425 <input id= "unwind" class="allocation-inputstyle" type="text" placeholder="Enter the Max Unwind Level" oninput="if(this.value > 512) this.value = '512'" onkeyup="this.value=this.value.replace(/\\D/g,'')" value="10"> 426 </div> 427 <div class="allocation-application"> 428 <span class="allocation-inner-font-style">Shared Memory Size (One page equals 4 KB)</span> 429 <span class="value-range">Shared Memory Size Range is 0 - 131072 page, default 16384 page</span> 430 <div> 431 <input id = "shareMemory" class="allocation-inputstyle" type="text" placeholder="Enter the Shared Memory Size" oninput="if(this.value > 131072) this.value = '131072'" onkeyup="this.value=this.value.replace(/\\D/g,'')" value="16384"> 432 <span>Page</span> 433 </div> 434 </div> 435 <div class="allocation-application"> 436 <span class="allocation-inner-font-style" >Filter Memory Size </span> 437 <span class="value-range">Filter size Range is 0 - 65535 byte, default 4096 byte</span> 438 <div> 439 <input id = "filterSized" class="allocation-inputstyle" type="text" placeholder="Enter the Filter Memory Size" oninput="if(this.value > 65535) this.value = '65535'" onkeyup="this.value=this.value.replace(/\\D/g,'')" value="4096"> 440 <span>Byte</span> 441 </div> 442 </div> 443 <div class="allocation-switchstyle"> 444 <span class="allocation-inner-font-style" id="fp-unwind">Use Fp Unwind</span> 445 <lit-switch class="lts" id="use_fp_unwind" title="fp unwind" checked="true"></lit-switch> 446 </div> 447 <div class="allocation-switchstyle"> 448 <span class="allocation-inner-font-style" id="record_accurately ">Use Record Accurately (Available on recent OpenHarmony 4.0)</span> 449 <lit-switch class="lts" id="use_record_accurately" title="record_accurately" checked="true"></lit-switch> 450 </div> 451 <div class="allocation-switchstyle"> 452 <span class="allocation-inner-font-style" id="offline_symbolization">Use Offline Symbolization (Available on recent OpenHarmony 4.0)</span> 453 <lit-switch class="lts" id="use_offline_symbolization" title="offline_symbolization" checked="true"></lit-switch> 454 </div> 455 <div class="allocation-switchstyle"> 456 <span class="allocation-inner-font-style" id="startup_mode">Use Startup Mode (Available on recent OpenHarmony 4.0)</span> 457 <lit-switch class="lts" id="use_startup_mode" title="startup_mode"></lit-switch> 458 </div> 459 <div class="allocation-switchstyle record-statistics-result" style="grid-row: 6; grid-column: 1 / 3;height: min-content;display: grid;grid-template-rows: 1fr;grid-template-columns: 1fr min-content;"> 460 <div class="record-title"> 461 <span class="record-mode">Use Record Statistics (Available on recent OpenHarmony 4.0)</span> 462 <span class="allocation-record-prompt"> Time between following interval (0 = disabled) </span> 463 </div> 464 <lit-slider id="interval-slider" defaultColor="var(--dark-color3,#46B1E3)" open dir="right"> 465 </lit-slider> 466 <div class='resultSize'> 467 <input class="interval-result" type="text" value='0' onkeyup="this.value=this.value.replace(/\\D/g,'')"> 468 <span style="text-align: center; margin: 8px"> S </span> 469 </div> 470 </div> 471 </div> 472 `; 473 } 474 475 private convertToValue(input: string, unit: string): number { 476 let value: number; 477 switch (unit) { 478 case 'MB': 479 value = Number(input) * 1024 * 1024; 480 break; 481 case 'KB': 482 value = Number(input) * 1024; 483 break; 484 default: 485 value = 0; 486 } 487 let number = value / 4096; 488 if (number > 0 && number < 1) { 489 return 16384; 490 } 491 return parseInt(String(number)); 492 } 493} 494