1/* 2 * Copyright (C) 2023 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 { 18 LitTable, 19 RedrawTreeForm, 20} from '../../../../../base-ui/table/lit-table'; 21import { SelectionParam } from '../../../../bean/BoxSelection'; 22import '../../../StackBar'; 23import { getTabRunningPercent } from '../../../../database/sql/ProcessThread.sql'; 24import { 25 queryCpuFreqUsageData, 26 queryCpuFreqFilterId, 27} from '../../../../database/sql/Cpu.sql'; 28import { Utils } from '../../base/Utils'; 29import { resizeObserver } from '../SheetUtils'; 30import { SpSegmentationChart } from '../../../chart/SpSegmentationChart'; 31import { 32 type CpuFreqData, 33 type RunningFreqData, 34 type RunningData, 35 type CpuFreqTd, 36} from './TabPaneFreqUsageConfig'; 37 38@element('tabpane-frequsage') 39export class TabPaneFreqUsage extends BaseElement { 40 private threadStatesTbl: LitTable | null | undefined; 41 private currentSelectionParam: SelectionParam | undefined; 42 private worker: Worker | undefined; 43 static element: TabPaneFreqUsage; 44 45 set data(threadStatesParam: SelectionParam) { 46 if (this.currentSelectionParam === threadStatesParam) { 47 return; 48 } 49 this.currentSelectionParam = threadStatesParam; 50 this.threadStatesTbl!.recycleDataSource = []; 51 // @ts-ignore 52 this.threadStatesTbl.value = []; 53 this.queryAllData(threadStatesParam); 54 } 55 56 static refresh(): void { 57 this.prototype.queryAllData(TabPaneFreqUsage.element.currentSelectionParam!); 58 } 59 60 async queryAllData(threadStatesParam: SelectionParam): Promise<void> { 61 TabPaneFreqUsage.element.threadStatesTbl!.loading = true; 62 let runningResult: Array<RunningData> = await getTabRunningPercent( 63 threadStatesParam.threadIds, 64 threadStatesParam.processIds, 65 threadStatesParam.leftNs, 66 threadStatesParam.rightNs 67 ); 68 // 查询cpu及id信息 69 let cpuIdResult: Array<{ id: number; cpu: number }> = 70 await queryCpuFreqFilterId(); 71 // 以键值对形式将cpu及id进行对应,后续会将频点数据与其对应cpu进行整合 72 let IdMap: Map<number, number> = new Map(); 73 let queryId: Array<number> = []; 74 let cpuArray: Array<number> = []; 75 for (let i = 0; i < cpuIdResult.length; i++) { 76 queryId.push(cpuIdResult[i].id); 77 IdMap.set(cpuIdResult[i].id, cpuIdResult[i].cpu); 78 cpuArray.push(cpuIdResult[i].cpu); 79 } 80 // 通过id去查询频点数据 81 let cpuFreqResult: Array<CpuFreqTd> = await queryCpuFreqUsageData(queryId); 82 let cpuFreqData: Array<CpuFreqData> = []; 83 for (let i of cpuFreqResult) { 84 cpuFreqData.push({ 85 ts: i.startNS + threadStatesParam.recordStartNs, 86 cpu: IdMap.get(i.filter_id)!, 87 value: i.value, 88 dur: i.dur, 89 }); 90 } 91 const LEFT_TIME: number = threadStatesParam.leftNs + threadStatesParam.recordStartNs; 92 const RIGHT_TIME: number = threadStatesParam.rightNs + threadStatesParam.recordStartNs; 93 const comPower = 94 SpSegmentationChart.freqInfoMapData.size > 0 95 ? SpSegmentationChart.freqInfoMapData 96 : undefined; 97 const args = { 98 runData: runningResult, 99 cpuFreqData: cpuFreqData, 100 leftNs: LEFT_TIME, 101 rightNs: RIGHT_TIME, 102 cpuArray: cpuArray, 103 comPower: comPower, 104 }; 105 TabPaneFreqUsage.element.worker!.postMessage(args); 106 TabPaneFreqUsage.element.worker!.onmessage = (event: MessageEvent): void => { 107 let resultArr: Array<RunningFreqData> = event.data; 108 TabPaneFreqUsage.element.fixedDeal(resultArr, threadStatesParam.traceId); 109 TabPaneFreqUsage.element.threadClick(resultArr); 110 TabPaneFreqUsage.element.threadStatesTbl!.recycleDataSource = resultArr; 111 TabPaneFreqUsage.element.threadStatesTbl!.loading = false; 112 }; 113 } 114 115 /** 116 * 表头点击事件 117 */ 118 private threadClick(data: Array<RunningFreqData>): void { 119 let labels = this.threadStatesTbl?.shadowRoot 120 ?.querySelector('.th > .td')! 121 .querySelectorAll('label'); 122 if (labels) { 123 for (let i = 0; i < labels.length; i++) { 124 let label = labels[i].innerHTML; 125 labels[i].addEventListener('click', (e) => { 126 if (label.includes('Process') && i === 0) { 127 this.threadStatesTbl!.setStatus(data, false); 128 this.threadStatesTbl!.recycleDs = 129 this.threadStatesTbl!.meauseTreeRowElement( 130 data, 131 RedrawTreeForm.Retract 132 ); 133 } else if (label.includes('Thread') && i === 1) { 134 for (let item of data) { 135 // @ts-ignore 136 item.status = true; 137 if (item.children !== undefined && item.children.length > 0) { 138 this.threadStatesTbl!.setStatus(item.children, false); 139 } 140 } 141 this.threadStatesTbl!.recycleDs = 142 this.threadStatesTbl!.meauseTreeRowElement( 143 data, 144 RedrawTreeForm.Retract 145 ); 146 } else if (label.includes('CPU') && i === 2) { 147 this.threadStatesTbl!.setStatus(data, true); 148 this.threadStatesTbl!.recycleDs = 149 this.threadStatesTbl!.meauseTreeRowElement( 150 data, 151 RedrawTreeForm.Expand 152 ); 153 } 154 }); 155 } 156 } 157 } 158 159 160 initElements(): void { 161 this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>( 162 '#tb-running-percent' 163 ); 164 //开启一个线程计算busyTime 165 this.worker = new Worker( 166 new URL('../../../../database/TabPaneFreqUsageWorker', import.meta.url) 167 ); 168 TabPaneFreqUsage.element = this; 169 } 170 171 connectedCallback(): void { 172 super.connectedCallback(); 173 resizeObserver(this.parentElement!, this.threadStatesTbl!, 20); 174 } 175 176 initHtml(): string { 177 return ` 178 <style> 179 :host{ 180 padding: 10px 10px; 181 display: flex; 182 flex-direction: column; 183 } 184 </style> 185 <lit-table id="tb-running-percent" style="height: auto; overflow-x:auto;" tree> 186 <lit-table-column class="running-percent-column" width="320px" title="Process/Thread/CPU" data-index="thread" key="thread" align="flex-start" retract> 187 </lit-table-column> 188 <lit-table-column class="running-percent-column" width="100px" title="CPU" data-index="cpu" key="cpu" align="flex-start"> 189 </lit-table-column> 190 <lit-table-column class="running-percent-column" width="240px" title="Consume(MHz*ms)" data-index="consumption" key="consumption" align="flex-start"> 191 </lit-table-column> 192 <lit-table-column class="running-percent-column" width="200px" title="Freq(MHz:Cap)" data-index="frequency" key="frequency" align="flex-start"> 193 </lit-table-column> 194 <lit-table-column class="running-percent-column" width="240px" title="Consume(cap*ms)" data-index="consumpower" key="consumpower" align="flex-start"> 195 </lit-table-column> 196 <lit-table-column class="running-percent-column" width="100px" title="TaskUtil(%)" data-index="cpuload" key="cpuload" align="flex-start"> 197 </lit-table-column> 198 <lit-table-column class="running-percent-column" width="200px" title="Dur(ms)" data-index="dur" key="dur" align="flex-start"> 199 </lit-table-column> 200 <lit-table-column class="running-percent-column" width="140px" title="Dur/All_Dur(%)" data-index="percent" key="percent" align="flex-start"> 201 </lit-table-column> 202 </lit-table> 203 `; 204 } 205 206 /** 207 * 递归整理数据小数位 208 */ 209 fixedDeal(arr: Array<RunningFreqData>, traceId?: string | null): void { 210 if (arr == undefined) { 211 return; 212 } 213 const TIME_MUTIPLE: number = 1000000; 214 // KHz->MHz * ns->ms 215 const CONS_MUTIPLE: number = 1000000000; 216 const MIN_PERCENT: number = 2; 217 const MIN_FREQ: number = 3; 218 const MIN_POWER: number = 6; 219 for (let i = 0; i < arr.length; i++) { 220 let trackId: number; 221 // 若存在空位元素则进行删除处理 222 if (arr[i] === undefined) { 223 arr.splice(i, 1); 224 i--; 225 continue; 226 } 227 if (arr[i].thread?.indexOf('P') !== -1) { 228 trackId = Number(arr[i].thread?.slice(1)!); 229 arr[i].thread = `${Utils.getInstance().getProcessMap(traceId).get(trackId) || 'Process'} ${trackId}`; 230 } else if (arr[i].thread === 'summary data') { 231 } else { 232 trackId = Number(arr[i].thread!.split('_')[1]); 233 arr[i].thread = `${Utils.getInstance().getThreadMap(traceId).get(trackId) || 'Thread'} ${trackId}`; 234 } 235 if (arr[i].cpu < 0) { 236 // @ts-ignore 237 arr[i].cpu = ''; 238 } 239 // @ts-ignore 240 if (arr[i].frequency < 0) { 241 arr[i].frequency = ''; 242 } 243 if (!arr[i].cpuload) { 244 // @ts-ignore 245 arr[i].cpuload = '0.000000'; 246 } else { 247 // @ts-ignore 248 arr[i].cpuload = arr[i].cpuload.toFixed(MIN_POWER); 249 } 250 // @ts-ignore 251 arr[i].percent = arr[i].percent.toFixed(MIN_PERCENT); 252 // @ts-ignore 253 arr[i].dur = (arr[i].dur / TIME_MUTIPLE).toFixed(MIN_FREQ); 254 // @ts-ignore 255 arr[i].consumption = (arr[i].consumption / CONS_MUTIPLE).toFixed(MIN_FREQ); 256 // @ts-ignore 257 arr[i].consumpower = (arr[i].consumpower / TIME_MUTIPLE).toFixed(MIN_FREQ); 258 if (arr[i].frequency !== '') { 259 if (arr[i].frequency === 'unknown') { 260 arr[i].frequency = 'unknown'; 261 } else { 262 arr[i].frequency = arr[i].frequency; 263 } 264 } 265 this.fixedDeal(arr[i].children!, traceId); 266 } 267 } 268}