1// @ts-nocheck 2/* 3 * Copyright (C) 2022 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; 18import {CpuStruct} from "../../../bean/CpuStruct.js"; 19import {LitTable} from "../../../../base-ui/table/lit-table.js"; 20import "../../../../base-ui/table/lit-table-column.js"; 21 22import { 23 queryBinderArgsByArgset, 24 queryWakeUpThread_WakeThread, 25 queryWakeUpThread_WakeTime 26} from "../../../database/SqlLite.js"; 27import {WakeupBean} from "../../../bean/WakeupBean.js"; 28import {ThreadStruct} from "../../../bean/ThreadStruct.js"; 29import {ProcessMemStruct} from "../../../bean/ProcessMemStruct.js"; 30import {FuncStruct} from "../../../bean/FuncStruct.js"; 31import {SpApplication} from "../../../SpApplication.js"; 32 33const STATUS_MAP: any = { 34 D: "Uninterruptible Sleep", 35 S: "Sleeping", 36 R: "Runnable", 37 "Running": "Running", 38 "R+": "Runnable (Preempted)", 39 DK: "Uninterruptible Sleep + Wake Kill", 40 I: "Task Dead", 41 T: "Stopped", 42 t: "Traced", 43 X: "Exit (Dead)", 44 Z: "Exit (Zombie)", 45 K: "Wake Kill", 46 W: "Waking", 47 P: "Parked", 48 N: "No Load" 49} 50const INPUT_WORD = "This is the interval from when the task became eligible to run \n(e.g.because of notifying a wait queue it was a suspended on) to\n when it started running." 51 52export function getTimeString(ns: number): string { 53 let currentNs = ns 54 let hour1 = 3600_000_000_000 55 let minute1 = 60_000_000_000 56 let second1 = 1_000_000_000; // 1 second 57 let millisecond1 = 1_000_000; // 1 millisecond 58 let microsecond1 = 1_000; // 1 microsecond 59 let res = ""; 60 if (currentNs >= hour1) { 61 res += Math.floor(currentNs / hour1) + "h "; 62 currentNs = currentNs - Math.floor(currentNs / hour1) * hour1 63 } 64 if (currentNs >= minute1) { 65 res += Math.floor(currentNs / minute1) + "m "; 66 currentNs = currentNs - Math.floor(ns / minute1) * minute1 67 } 68 if (currentNs >= second1) { 69 res += Math.floor(currentNs / second1) + "s "; 70 currentNs = currentNs - Math.floor(currentNs / second1) * second1 71 } 72 if (currentNs >= millisecond1) { 73 res += Math.floor(currentNs / millisecond1) + "ms "; 74 currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1 75 } 76 if (currentNs >= microsecond1) { 77 res += Math.floor(currentNs / microsecond1) + "μs "; 78 currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1 79 } 80 if (currentNs > 0) { 81 res += currentNs + "ns "; 82 } 83 return res 84} 85 86@element('tabpane-current-selection') 87export class TabPaneCurrentSelection extends BaseElement { 88 weakUpBean: WakeupBean | null | undefined; 89 private tbl: LitTable | null | undefined; 90 private tableObserver: MutationObserver | undefined 91 // @ts-ignore 92 private dpr: any = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1; 93 94 set data(value: any) { 95 this.setCpuData(value) 96 } 97 98 setCpuData(data: CpuStruct, callback: ((data: WakeupBean | null) => void) | undefined = undefined) { 99 let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle"); 100 if (leftTitle) { 101 leftTitle.innerText = "Slice Details" 102 } 103 let list: any[] = [] 104 let process = data.processName 105 let processId = data.processId 106 if (process == null || process == "") { 107 process = data.name 108 processId = data.tid 109 } 110 let state = "" 111 if (data.end_state) { 112 state = STATUS_MAP[data.end_state] 113 } else if (data.end_state == "" || data.end_state == null) { 114 state = "" 115 } else { 116 state = "Unknown State" 117 } 118 list.push({name: 'Process', value: `${process || 'Process'} [${processId}]`}) 119 list.push({name: 'Thread', value: `${data.name || 'Process'} [${data.tid}]`}) 120 list.push({name: 'CmdLine', value: data.processCmdLine}) 121 list.push({name: 'StartTime', value: getTimeString(data.startTime || 0)}) 122 list.push({name: 'Duration', value: getTimeString(data.dur || 0)}) 123 list.push({name: 'Prio', value: data.priority || 0}) 124 list.push({name: 'End State', value: state}) 125 this.queryWakeUpData(data).then((bean) => { 126 if (callback) { 127 callback(bean) 128 } 129 this.tbl!.dataSource = list 130 let rightArea: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#right-table"); 131 let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle"); 132 let canvas = this.initCanvas(); 133 if (bean != null) { 134 this.weakUpBean = bean; 135 if (rightArea != null && rightArea) { 136 rightArea.style.visibility = "visible" 137 } 138 if (rightTitle != null && rightTitle) { 139 rightTitle.style.visibility = "visible" 140 } 141 this.drawRight(canvas, bean) 142 } else { 143 this.weakUpBean = null; 144 if (rightArea != null && rightArea) { 145 rightArea.style.visibility = "hidden" 146 } 147 if (rightTitle != null && rightTitle) { 148 rightTitle.style.visibility = "hidden" 149 } 150 } 151 }) 152 } 153 154 setFunctionData(data: FuncStruct) {//方法信息 155 this.initCanvas() 156 let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle"); 157 let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle"); 158 if (rightTitle) { 159 rightTitle.style.visibility = "hidden" 160 } 161 if (leftTitle) { 162 leftTitle.innerText = "Slice Details" 163 } 164 let list: any[] = [] 165 list.push({name: 'Name', value: data.funName}) 166 list.push({name: 'StartTime', value: getTimeString(data.startTs || 0)}) 167 list.push({name: 'Duration', value: getTimeString(data.dur || 0)}) 168 if (FuncStruct.isBinder(data)) { 169 if (data.argsetid != undefined) { 170 queryBinderArgsByArgset(data.argsetid).then((argset) => { 171 argset.forEach((item) => { 172 list.push({name: item.keyName, value: item.strValue}) 173 }) 174 175 }); 176 } 177 list.push({name: 'depth', value: data.depth}) 178 list.push({name: 'arg_set_id', value: data.argsetid}) 179 } 180 this.tbl!.dataSource = list 181 182 } 183 184 setMemData(data: ProcessMemStruct) { 185 this.initCanvas() 186 let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle"); 187 if (leftTitle) { 188 leftTitle.innerText = "Counter Details" 189 } 190 let list: any[] = [] 191 list.push({name: 'Start time', value: getTimeString(data.startTime || 0)}) 192 list.push({name: 'Value', value: data.value}) 193 list.push({name: 'Delta', value: data.delta}) 194 list.push({name: 'Duration', value: getTimeString(data.duration || 0)}) 195 this.tbl!.dataSource = list 196 197 } 198 199 setThreadData(data: ThreadStruct) { 200 this.initCanvas() 201 let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle"); 202 let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle"); 203 if (rightTitle) { 204 rightTitle.style.visibility = "hidden" 205 } 206 if (leftTitle) { 207 leftTitle.innerText = "Counter Details" 208 } 209 let list: any[] = [] 210 list.push({name: 'StartTime', value: getTimeString(data.startTime || 0)}) 211 list.push({name: 'Duration', value: getTimeString(data.dur || 0)}) 212 let state = "" 213 if (data.state) { 214 state = STATUS_MAP[data.state] 215 } else if (data.state == "" || data.state == null) { 216 state = "" 217 } else { 218 state = "Unknown State" 219 } 220 if ("Running" == state) { 221 state = state + " on CPU " + data.cpu; 222 } 223 list.push({name: 'State', value: state}) 224 let processName = data.processName; 225 if (processName == null || processName == "" || processName.toLowerCase() == "null") { 226 processName = data.name; 227 } 228 list.push({name: 'Process', value: processName + " [" + data.pid + "] "}) 229 this.tbl!.dataSource = list 230 } 231 232 233 async queryWakeUpData(data: CpuStruct) { 234 let wb: WakeupBean | null = null 235 if (data.id == undefined || data.startTime == undefined) { 236 return null 237 } 238 let wakeupTimes = await queryWakeUpThread_WakeTime(data.id, data.startTime)// 3,4835380000 239 if (wakeupTimes != undefined && wakeupTimes.length > 0) { 240 let wakeupTime = wakeupTimes[0] 241 if (wakeupTime.wakeTs != undefined && wakeupTime.preRow != undefined && wakeupTime.wakeTs < wakeupTime.preRow) { 242 return null 243 } 244 if (wakeupTime.wakeTs == undefined) { 245 return null 246 } 247 let wakeupBeans = await queryWakeUpThread_WakeThread(wakeupTime.wakeTs) 248 if (wakeupBeans != undefined && wakeupBeans.length > 0) { 249 wb = wakeupBeans[0] 250 if (wb != null) { 251 if (wakeupTime.wakeTs != undefined && wakeupTime.startTs != undefined) { 252 wb.wakeupTime = wakeupTime.wakeTs - wakeupTime.startTs 253 } 254 wb.schedulingLatency = data.startTime || 0 - (wb.wakeupTime || 0) 255 if (wb.process == null) { 256 wb.process = wb.thread; 257 } 258 if (wb.pid == undefined) { 259 wb.pid = wb.tid; 260 } 261 wb.schedulingDesc = INPUT_WORD 262 } 263 } 264 } 265 return wb 266 } 267 268 initCanvas(): HTMLCanvasElement | null { 269 let canvas = this.shadowRoot!.querySelector("#rightDraw") 270 let width = getComputedStyle(this.tbl!).getPropertyValue("width") 271 let height = getComputedStyle(this.tbl!).getPropertyValue("height") 272 if (canvas != null) { 273 canvas.width = Math.round(Number(width.replace("px", "")) * this.dpr) 274 canvas.height = Math.round(Number(height.replace("px", "")) * this.dpr) 275 canvas.style.width = width 276 canvas.style.height = height 277 } 278 SpApplication.skinChange = (val: boolean) => { 279 this.drawRight(canvas, this.weakUpBean) 280 } 281 return canvas 282 } 283 284 drawRight(cavs: HTMLCanvasElement | null, wakeupBean: WakeupBean | null) { 285 if (cavs == null) { 286 return 287 } 288 let context = cavs.getContext("2d"); 289 if (context != null) { 290 if (document.querySelector<SpApplication>("sp-application").dark) { 291 context.strokeStyle = "#ffffff"; 292 context.fillStyle = "#ffffff"; 293 } else { 294 context.strokeStyle = "#000000"; 295 context.fillStyle = "#000000"; 296 } 297 context.lineWidth = this.dprToPx(2); 298 context.moveTo(this.dprToPx(10), this.dprToPx(15)) 299 context.lineTo(this.dprToPx(10), this.dprToPx(125)) 300 context.stroke(); 301 //绘制菱形 302 context.lineWidth = this.dprToPx(1); 303 context.beginPath() 304 context.moveTo(this.dprToPx(10), this.dprToPx(30)) 305 context.lineTo(this.dprToPx(4), this.dprToPx(40)) 306 context.lineTo(this.dprToPx(10), this.dprToPx(50)) 307 context.lineTo(this.dprToPx(16), this.dprToPx(40)) 308 context.lineTo(this.dprToPx(10), this.dprToPx(30)) 309 context.closePath() 310 context.fill() 311 context.font = this.dprToPx(12) + "px sans-serif"; 312 let strList = [] 313 strList.push("wakeup @ " + getTimeString(wakeupBean?.wakeupTime || 0) + " on CPU " + wakeupBean?.cpu + " by") 314 strList.push("P:" + wakeupBean?.process + " [ " + wakeupBean?.pid + " ]") 315 strList.push("F:" + wakeupBean?.thread + " [ " + wakeupBean?.tid + " ]") 316 strList.forEach((str, index) => { 317 if (context != null) { 318 context.fillText(str 319 , this.dprToPx(40), this.dprToPx(40 + 16 * index)) 320 } 321 }) 322 context.lineWidth = this.dprToPx(2); 323 context.lineJoin = "bevel" 324 context.moveTo(this.dprToPx(10), this.dprToPx(95)) 325 context.lineTo(this.dprToPx(20), this.dprToPx(90)) 326 context.moveTo(this.dprToPx(10), this.dprToPx(95)) 327 context.lineTo(this.dprToPx(20), this.dprToPx(100)) 328 context.moveTo(this.dprToPx(10), this.dprToPx(95)) 329 context.lineTo(this.dprToPx(80), this.dprToPx(95)) 330 context.lineTo(this.dprToPx(70), this.dprToPx(90)) 331 context.moveTo(this.dprToPx(80), this.dprToPx(95)) 332 context.lineTo(this.dprToPx(70), this.dprToPx(100)) 333 context.stroke(); 334 context.font = this.dprToPx(12) + "px sans-serif"; 335 context.fillText("Scheduling latency:" + getTimeString(wakeupBean?.schedulingLatency || 0) 336 , this.dprToPx(90), this.dprToPx(100)) 337 context.font = this.dprToPx(10) + "px sans-serif"; 338 INPUT_WORD.split("\n").forEach((str, index) => { 339 context?.fillText(str 340 , this.dprToPx(90), this.dprToPx(120 + 12 * index)) 341 }) 342 343 } 344 } 345 346 dprToPx(num: number) { 347 return Math.round(num * this.dpr) 348 } 349 350 initElements(): void { 351 this.tbl = this.shadowRoot?.querySelector<LitTable>('#selectionTbl'); 352 this.tbl.addEventListener("column-click", ev => { 353 console.log(ev.detail); 354 }) 355 this.addTableObserver() 356 } 357 358 addTableObserver() { 359 let MutationObserver = window.MutationObserver 360 this.tableObserver = new MutationObserver((list) => { 361 console.log(this.tbl); 362 if (this.tbl) { 363 let width = getComputedStyle(this.tbl).getPropertyValue("width") 364 let height = getComputedStyle(this.tbl).getPropertyValue("height") 365 console.log(width); 366 console.log(height); 367 } 368 }) 369 let selector = this.shadowRoot?.querySelector(".left-table"); 370 this.tableObserver?.observe(selector!, {attributes: true, attributeFilter: ['style'], attributeOldValue: true}) 371 } 372 373 initHtml(): string { 374 return ` 375 <style> 376 .current-title{ 377 width: 100%; 378 display: flex; 379 top: 0; 380 background: var(--dark-background,#ffffff); 381 position: sticky; 382 } 383 .current-title h2{ 384 width: 50%; 385 padding: 0 10px; 386 font-size: 16px; 387 font-weight: 400; 388 visibility: visible; 389 } 390 .bottom-scroll-area{ 391 display: flex; 392 height: auto; 393 overflow-y: auto; 394 } 395 .left-table{ 396 width: 50%; 397 padding: 0 10px; 398 } 399 .right-table{ 400 width: 50%; 401 } 402 </style> 403 <div style="width: 100%;height: auto;position: relative"> 404 <div class="current-title"> 405 <h2 id="leftTitle"></h2> 406 <h2 id="rightTitle">Scheduling Latency</h2> 407 </div> 408 <div class="bottom-scroll-area"> 409 <div class="left-table"> 410 <lit-table id="selectionTbl" no-head style="height: auto"> 411 <lit-table-column title="name" data-index="name" key="name" align="flex-start" width="180px"> 412 <template><div>{{name}}</div></template> 413 </lit-table-column> 414 <lit-table-column title="value" data-index="value" key="value" align="flex-start" ></lit-table-column> 415 </lit-table> 416 </div> 417 <div class="right-table"> 418 <canvas id="rightDraw" style="width: 100%;height: 100%;"></canvas> 419 </div> 420 </div> 421 </div> 422 `; 423 } 424 425} 426