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 {LitTable} from "../../../../base-ui/table/lit-table.js"; 18import {SelectionData, SelectionParam} from "../../../bean/BoxSelection.js"; 19import "../../StackBar.js" 20import {getTabThreadStates} from "../../../database/SqlLite.js"; 21import {Utils} from "../base/Utils.js"; 22import {StackBar} from "../../StackBar.js"; 23import {log} from "../../../../log/Log.js"; 24 25@element('tabpane-thread-states') 26export class TabPaneThreadStates extends BaseElement { 27 private tbl: LitTable | null | undefined; 28 private range: HTMLLabelElement | null | undefined; 29 private stackBar: StackBar | null | undefined; 30 private source: Array<SelectionData> = [] 31 32 set data(val: SelectionParam | any) { 33 //@ts-ignore 34 this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 45) + "px"; 35 // // @ts-ignore 36 this.range!.textContent = "Selected range: " + ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5) + " ms" 37 getTabThreadStates(val.threadIds, val.leftNs, val.rightNs).then((result) => { 38 if (result != null && result.length > 0) { 39 log("getTabThreadStates result size : " + result.length) 40 let sumWall = 0.0; 41 let sumOcc = 0; 42 for (let e of result) { 43 e.process = e.process == null || e.process.length == 0 ? "[NULL]" : e.process 44 e.thread = e.thread == null || e.thread.length == 0 ? "[NULL]" : e.thread 45 sumWall += e.wallDuration 46 sumOcc += e.occurrences 47 e.stateJX = e.state 48 e.state = Utils.getEndState(e.stateJX); 49 e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); 50 e.avgDuration = parseFloat((e.avgDuration / 1000000.0).toFixed(5)); 51 } 52 let count = new SelectionData() 53 count.process = " " 54 count.state = " " 55 count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(5)); 56 count.occurrences = sumOcc; 57 result.splice(0, 0, count) 58 this.source = result; 59 this.tbl!.recycleDataSource = result 60 this.stackBar!.data = result; 61 } else { 62 this.source = [] 63 this.stackBar!.data = [] 64 this.tbl!.recycleDataSource = [] 65 } 66 }) 67 } 68 69 initElements(): void { 70 this.tbl = this.shadowRoot?.querySelector<LitTable>('#tb-thread-states'); 71 this.range = this.shadowRoot?.querySelector('#time-range'); 72 this.stackBar = this.shadowRoot?.querySelector('#stack-bar'); 73 this.tbl!.addEventListener('column-click', (evt: any) => { 74 this.sortByColumn(evt.detail) 75 }); 76 new ResizeObserver((entries) => { 77 if (this.parentElement?.clientHeight != 0) { 78 // @ts-ignore 79 this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" 80 this.tbl?.reMeauseHeight() 81 } 82 }).observe(this.parentElement!) 83 } 84 85 initHtml(): string { 86 return ` 87 <style> 88 :host{ 89 display: flex; 90 flex-direction: column; 91 padding: 10px 10px; 92 } 93 </style> 94 <div style="display: flex;height: 20px;align-items: center;flex-direction: row;margin-bottom: 5px"> 95 <stack-bar id="stack-bar" style="flex: 1"></stack-bar> 96 <label id="time-range" style="width: auto;text-align: end;font-size: 10pt;">Selected range:0.0 ms</label> 97 </div> 98 <lit-table id="tb-thread-states" style="height: auto"> 99 <lit-table-column width="25%" title="Process" data-index="process" key="process" align="flex-start" order> 100 </lit-table-column> 101 <lit-table-column width="1fr" title="PID" data-index="pid" key="pid" align="flex-start" order > 102 </lit-table-column> 103 <lit-table-column width="20%" title="Thread" data-index="thread" key="thread" align="flex-start" order > 104 </lit-table-column> 105 <lit-table-column width="1fr" title="TID" data-index="tid" key="tid" align="flex-start" order > 106 </lit-table-column> 107 <lit-table-column width="1fr" title="State" data-index="state" key="state" align="flex-start" order > 108 </lit-table-column> 109 <lit-table-column width="1fr" title="Wall duration(ms)" data-index="wallDuration" key="wallDuration" align="flex-start" order > 110 </lit-table-column> 111 <lit-table-column width="1fr" title="Avg Wall duration(ms)" data-index="avgDuration" key="avgDuration" align="flex-start" order > 112 </lit-table-column> 113 <lit-table-column width="1fr" title="Occurrences" data-index="occurrences" key="occurrences" align="flex-start" order > 114 </lit-table-column> 115 </lit-table> 116 `; 117 } 118 119 sortByColumn(detail: any) { 120 function compare(property: any, sort: any, type: any) { 121 return function (a: SelectionData | any, b: SelectionData | any) { 122 if (a.process == " " || b.process == " ") { 123 return 0; 124 } 125 if (type === 'number') { 126 return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); 127 } else { 128 if (b[property] > a[property]) { 129 return sort === 2 ? 1 : -1; 130 } else if (b[property] == a[property]) { 131 return 0; 132 } else { 133 return sort === 2 ? -1 : 1; 134 } 135 } 136 } 137 } 138 139 if (detail.key === "name" || detail.key === "thread" || detail.key === "state") { 140 this.source.sort(compare(detail.key, detail.sort, 'string')) 141 } else { 142 this.source.sort(compare(detail.key, detail.sort, 'number')) 143 } 144 this.tbl!.recycleDataSource = this.source; 145 } 146 147}