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