diff --git a/ide/src/base-ui/table/lit-table.ts b/ide/src/base-ui/table/lit-table.ts index aff95ebf7028ed159097411007ca9a771b21c135..0070821a2deb1ac8b38a218b7a58c9c3302c583c 100644 --- a/ide/src/base-ui/table/lit-table.ts +++ b/ide/src/base-ui/table/lit-table.ts @@ -230,6 +230,27 @@ export class LitTable extends HTMLElement { width: 15px; height: 15px; } + .button-icon{ + height: 32px; + width: 164px; + color: black; + font-size: 14px; + border: 1px solid black; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + cursor: pointer; + background: var(--dark-background3,#FFFFFF); + border-radius: 20px; + padding: 15px; + transition: opacity 0.2s; + outline: none; + position: relative; + } + .button-icon:active { + background: var(--dark-background1,#f5f5f5) + } .mouse-select{ background-color: var(--dark-background6,#DEEDFF); } @@ -778,6 +799,23 @@ export class LitTable extends HTMLElement { ); }; } + if (a.hasAttribute('button')) { + let buttonIcon = document.createElement('button'); + buttonIcon.innerHTML = 'GetBusyTime(ms)'; + buttonIcon.classList.add('button-icon'); + h.appendChild(buttonIcon); + buttonIcon.addEventListener('click', (event) => { + this.dispatchEvent( + new CustomEvent('button-click', { + detail: { + key: key + }, + composed: true + }) + ); + event.stopPropagation() + }) + } h.style.justifyContent = a.getAttribute('align'); this.gridTemplateColumns.push(a.getAttribute('width') || '1fr'); h.style.gridArea = key; diff --git a/ide/src/trace/bean/BoxSelection.ts b/ide/src/trace/bean/BoxSelection.ts index 0e18d1c5662f9a6d553c84fe54b2a9c3a50e8cc8..94a32ac7cc65e9e71ee8e07835ebcde33f442d69 100644 --- a/ide/src/trace/bean/BoxSelection.ts +++ b/ide/src/trace/bean/BoxSelection.ts @@ -40,8 +40,11 @@ export class SelectionParam { isCurrentPane: boolean = false; startup: boolean = false; staticInit: boolean = false; - + cpus: Array = []; + cpuStateRowsId: Array = []; + //新增框选cpu freq row名 + cpuFreqFilterNames: Array = []; cpuStateFilterIds: Array = []; cpuFreqFilterIds: Array = []; cpuFreqLimitDatas: Array> = []; @@ -88,11 +91,11 @@ export class SelectionParam { gpuTotal: boolean; gpuWindow: boolean; } = { - gl: false, - graph: false, - gpuWindow: false, - gpuTotal: false, - }; + gl: false, + graph: false, + gpuWindow: false, + gpuTotal: false, + }; purgeableTotalAbility: Array = []; purgeableTotalVM: Array = []; purgeablePinAbility: Array = []; diff --git a/ide/src/trace/component/SpSystemTrace.ts b/ide/src/trace/component/SpSystemTrace.ts index 57ee013d482fa017794844be62b2b4a958b6ad60..47e23a511596532fe1ad8a9825c3aeb4967f3c97 100644 --- a/ide/src/trace/component/SpSystemTrace.ts +++ b/ide/src/trace/component/SpSystemTrace.ts @@ -148,6 +148,7 @@ export class SpSystemTrace extends BaseElement { intersectionObserver: IntersectionObserver | undefined; tipEL: HTMLDivElement | undefined | null; rowsEL: HTMLDivElement | undefined | null; + stateRowsId: Array = []; rowsPaneEL: HTMLDivElement | undefined | null; spacerEL: HTMLDivElement | undefined | null; visibleRows: Array> = []; @@ -620,6 +621,7 @@ export class SpSystemTrace extends BaseElement { this.rangeTraceRow = []; } let selection = new SelectionParam(); + selection.cpuStateRowsId = this.stateRowsId; selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0; selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0; selection.recordStartNs = (window as any).recordStartNS; @@ -634,9 +636,13 @@ export class SpSystemTrace extends BaseElement { } } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ) { let filterId = parseInt(it.rowId!); + let filterName = it.name!; if (selection.cpuFreqFilterIds.indexOf(filterId) == -1) { selection.cpuFreqFilterIds.push(filterId); } + if (selection.cpuFreqFilterNames.indexOf(filterName) == -1) { + selection.cpuFreqFilterNames.push(filterName) + } } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ_LIMIT) { selection.cpuFreqLimitDatas.push(it.dataList!); } else if (it.rowType == TraceRow.ROW_TYPE_PROCESS) { diff --git a/ide/src/trace/component/chart/SpFreqChart.ts b/ide/src/trace/component/chart/SpFreqChart.ts index 7836fb63bbbd07d174051848c963768afc89c95e..cde8e498318349fd48a61e8c3b7ca797af102b1c 100644 --- a/ide/src/trace/component/chart/SpFreqChart.ts +++ b/ide/src/trace/component/chart/SpFreqChart.ts @@ -58,6 +58,7 @@ export class SpFreqChart { let maxFreqObj = Utils.getFrequencyWithUnit(freqMaxList[0].maxFreq); CpuFreqStruct.maxFreq = maxFreqObj.maxFreq; CpuFreqStruct.maxFreqName = maxFreqObj.maxFreqName; + this.trace.stateRowsId = cpuStateFilterIds; for (let i = 0; i < freqList.length; i++) { const it = freqList[i]; let traceRow = TraceRow.skeleton(); diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts index e3bc07c62c8296b4d64b37c32b0204dc100d8294..37c0e69f27b43a881cc8b256eed987182cd38444 100644 --- a/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts @@ -16,7 +16,7 @@ import { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; import { LitTable } from '../../../../../base-ui/table/lit-table.js'; import { SelectionParam } from '../../../../bean/BoxSelection.js'; -import { getTabPaneFrequencySampleData } from '../../../../database/SqlLite.js'; +import { getTabPaneFrequencySampleData, getTabPaneCounterSampleData } from '../../../../database/SqlLite.js'; import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; import { Utils } from '../../base/Utils.js'; import { ColorUtils } from '../../base/ColorUtils.js'; @@ -37,7 +37,6 @@ export class TabPaneFrequencySample extends BaseElement { private range: HTMLLabelElement | null | undefined; private loadDataInCache: boolean = true; private selectionParam: SelectionParam | null | undefined; - private frequencyProgressEL: LitProgressBar | null | undefined; private frequencyLoadingPage: any; private frequencyLoadingList: number[] = []; private frequencySampleSource: any[] = []; @@ -45,13 +44,16 @@ export class TabPaneFrequencySample extends BaseElement { private frequencySampleSortType: number = 0; private systemTrace: SpSystemTrace | undefined | null; private _rangeRow: Array> | undefined | null; + private frequencySampleClickKey: string = 'busyTimeStr'; + private frequencySampleClickType: boolean = false; + private busyTimeLoadingHide: boolean = false; + private freqBusyDataList: Array = []; + private worker: Worker | undefined; set data(frequencySampleValue: SelectionParam | any) { if (frequencySampleValue == this.selectionParam) { return; } - this.frequencyProgressEL!.loading = true; - this.frequencyLoadingPage.style.visibility = 'visible'; this.selectionParam = frequencySampleValue; // @ts-ignore this.frequencySampleTbl!.shadowRoot?.querySelector('.table').style.height = @@ -64,7 +66,6 @@ export class TabPaneFrequencySample extends BaseElement { } initElements(): void { - this.frequencyProgressEL = this.shadowRoot!.querySelector('.progressFre'); this.frequencyLoadingPage = this.shadowRoot!.querySelector('.loadingFre'); this.frequencySampleTbl = this.shadowRoot!.querySelector('#tb-states'); this.systemTrace = document @@ -99,7 +100,7 @@ export class TabPaneFrequencySample extends BaseElement { freqFilter[i].value === data.value && freqFilter[i].cpu === data.cpu && Math.max(TraceRow.rangeSelectObject?.startNS!, freqFilter[i].startNS!) < - Math.min(TraceRow.rangeSelectObject?.endNS!, freqFilter[i].startNS! + freqFilter[i].dur!) + Math.min(TraceRow.rangeSelectObject?.endNS!, freqFilter[i].startNS! + freqFilter[i].dur!) ) { CpuFreqStruct.hoverCpuFreqStruct = freqFilter[i]; } @@ -131,6 +132,13 @@ export class TabPaneFrequencySample extends BaseElement { } } }); + this.frequencySampleTbl!.addEventListener('button-click', (evt) => { + //@ts-ignore + this.frequencySampleClickKey = evt.detail.key; + this.frequencySampleClickType = !this.frequencySampleClickType + //@ts-ignore + this.handleClick(evt.detail.key, this.frequencySampleClickType) + }) } connectedCallback() { @@ -138,37 +146,74 @@ export class TabPaneFrequencySample extends BaseElement { resizeObserver(this.parentElement!, this.frequencySampleTbl!, 25, this.frequencyLoadingPage, 24); } - queryDataByDB(frqSampleParam: SelectionParam | any) { - this.frequencyLoadingList.push(1); - this.frequencyProgressEL!.loading = true; - this.frequencyLoadingPage.style.visibility = 'visible'; - getTabPaneFrequencySampleData( + async queryDataByDB(frqSampleParam: SelectionParam | any) { + let sampleMap = new Map(); + let frqSampleList = new Array(); + let stateFiliterIds: Array = []; + let cpuFiliterOrder: Array = []; + this.frequencySampleTbl!.loading = true; + if (this.frequencySampleClickType) this.frequencySampleClickType = !this.frequencySampleClickType; + if (this.busyTimeLoadingHide) this.busyTimeLoadingHide = !this.busyTimeLoadingHide; + let result = await getTabPaneFrequencySampleData( frqSampleParam.leftNs + frqSampleParam.recordStartNs, frqSampleParam.rightNs + frqSampleParam.recordStartNs, frqSampleParam.cpuFreqFilterIds - ).then((result) => { - this.frequencyLoadingList.splice(0, 1); - if (this.frequencyLoadingList.length == 0) { - this.frequencyProgressEL!.loading = false; - this.frequencyLoadingPage.style.visibility = 'hidden'; - } - let sampleMap = new Map(); - frqSampleParam.cpuFreqFilterIds.forEach((a: number) => { - this.getInitTime( - result.filter((f) => f.filterId == a), - sampleMap, - frqSampleParam - ); + ) + frqSampleParam.cpuFreqFilterIds.forEach((a: number) => { + this.getInitTime( + result.filter((f) => f.filterId == a), + sampleMap, + frqSampleParam + ); + }); + sampleMap.forEach((a) => { + a.timeStr = parseFloat((a.time / 1000000.0).toFixed(6)); + frqSampleList.push(a); + }); + this.frequencySampleSource = frqSampleList; + this.frequencySampleTbl!.loading = false; + this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType); + //找出框选的cpu fre所对应的cpu state + this.freqBusyDataList = []; + if (!frqSampleParam.cpuStateRowsId.length) { + sampleMap.forEach((value: any) => { + value.busyTime = 'NULL'; + this.freqBusyDataList.push(value); }); - - let frqSampleList: Array = []; - sampleMap.forEach((a) => { - a.timeStr = parseFloat((a.time / 1000000.0).toFixed(6)); - frqSampleList.push(a); + } else { + frqSampleParam.cpuFreqFilterNames.forEach((item: string) => { + let cpuStateIds = frqSampleParam.cpuStateRowsId.filter((it: any) => it.cpu == item.replace(/[^\d]/g, ' ').trim()); + stateFiliterIds.push(cpuStateIds[0].filterId); + cpuFiliterOrder.push(cpuStateIds[0].cpu) }); - this.frequencySampleSource = frqSampleList; - this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType); - }); + let res = await getTabPaneCounterSampleData( + frqSampleParam.leftNs + frqSampleParam.recordStartNs, + frqSampleParam.rightNs + frqSampleParam.recordStartNs, + stateFiliterIds + ); + //开启一个线程计算busyTime + this.worker = new Worker('trace/database/StateBusyTimeWorker.js'); + let msg = { + frqSampleParam, + result, + sampleMap, + res, + cpuFiliterOrder + }; + this.worker!.postMessage(msg); + this.worker!.onmessage = (event: MessageEvent) => { + sampleMap = event.data; + sampleMap.forEach((value) => { + this.freqBusyDataList.push(value); + }); + this.busyTimeLoadingHide = true; + //当busyTimebutton的状态为true但busyTime的计算未完成时 + if (this.frequencySampleClickType) { + this.handleClick(this.frequencySampleSortKey, this.frequencySampleClickType); + }; + this.worker!.terminate(); + }; + } } getInitTime(initFreqResult: Array, sampleMap: Map, selectionParam: SelectionParam) { @@ -197,11 +242,32 @@ export class TabPaneFrequencySample extends BaseElement { ...item, counter: 'Cpu ' + item.cpu, valueStr: ColorUtils.formatNumberComma(item.value), + busyTimeStr: '-', + busyTime: 0 }); } }); } + //点击按钮控制busyTime显示与否 + handleClick(key: string, type: boolean) { + let res = new Array(); + //当busyTime的值计算完毕后进入if判断 + if (this.busyTimeLoadingHide) { + this.busyTimeLoadingHide = false; + this.frequencySampleSource = this.freqBusyDataList; + this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType); + } + this.frequencySampleTbl!.loading = this.freqBusyDataList.length > 0 ? false : true; + if (this.freqBusyDataList.length > 0) { + this.frequencySampleTbl!.recycleDataSource.forEach((value) => { + value.busyTimeStr = type ? value.busyTime : '-'; + res.push(value) + }) + this.frequencySampleTbl!.recycleDataSource = res; + } + } + sortTable(key: string, type: number) { if (type == 0) { this.frequencySampleTbl!.recycleDataSource = this.frequencySampleSource; @@ -228,6 +294,12 @@ export class TabPaneFrequencySample extends BaseElement { } else { return frequencySampleRightData.value - frequencySampleLeftData.value; } + } else if (key == 'busyTimeStr') { + if (type == 1) { + return frequencySampleLeftData.busyTimeStr - frequencySampleRightData.busyTimeStr; + } else { + return frequencySampleRightData.busyTimeStr - frequencySampleLeftData.busyTimeStr; + } } else { return 0; } @@ -239,27 +311,11 @@ export class TabPaneFrequencySample extends BaseElement { initHtml(): string { return ` @@ -268,9 +324,9 @@ export class TabPaneFrequencySample extends BaseElement { + + - -
`; } } diff --git a/ide/src/trace/database/StateBusyTimeWorker.ts b/ide/src/trace/database/StateBusyTimeWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..3eea87b12f02b7176b72e60e59a7a5428a53c241 --- /dev/null +++ b/ide/src/trace/database/StateBusyTimeWorker.ts @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function getBusyTime(initFreqResult: Array, initStateResult: Array, sampleMap: Map, leftStartNs: number, rightEndNs: number) { + if (initFreqResult.length == 0) return; + if (initStateResult.length == 0) return; + //处理被框选的freq的第一个数据 + let includeData = initFreqResult.findIndex((a) => a.ts >= leftStartNs); + if (includeData !== 0) { + initFreqResult = initFreqResult.slice( + includeData == -1 ? initFreqResult.length - 1 : includeData - 1, + initFreqResult.length + ) + } + let startNS = includeData == 0 ? initFreqResult[0].ts : leftStartNs; + if (initFreqResult[0].ts < leftStartNs && includeData !== 0) initFreqResult[0].ts - leftStartNs; + //处理对应的state泳道被框选的第一个数据 + let includeStateData = initStateResult.findIndex((a) => a.ts >= startNS); + if (includeStateData !== 0) { + initStateResult = initStateResult.slice( + includeStateData == -1 ? initStateResult.length - 1 : includeStateData - 1, + initStateResult.length + ) + } + if (initStateResult[0].ts < startNS && includeStateData !== 0 && includeStateData !== -1) initStateResult[0].ts = startNS; + //处理被框选的freq最后一个数据 + if (initFreqResult[initFreqResult.length - 1].ts != rightEndNs) { + initFreqResult.push({ + ts: rightEndNs, + value: initFreqResult[initFreqResult.length - 1].value, + filterId: initFreqResult[initFreqResult.length - 1].filterId + }) + } + //处理被框选的freq最后一个数据 + if (initStateResult[initStateResult.length - 1].ts != rightEndNs) { + initStateResult.push({ + ts: rightEndNs, + value: initStateResult[initStateResult.length - 1].value + }) + } + let freqIndex = 1; + let stateIndex = 1; + let beginNs = startNS; + //value和Id的起始值是第0项 + let freqId = initFreqResult[0].filterId; + let freqVal = initFreqResult[0].value; + let stateVal = initStateResult[0].value; + //从index = 1开始循环 + while (freqIndex < initFreqResult.length && stateIndex < initStateResult.length) { + let newBeginNs = beginNs; + let newfreqId = freqId; + let newfreqVal = freqVal; + let newStateVal = stateVal; + let busyTime = 0; + //比较ts值,每次比较取ts相对小的那一项 + if (initFreqResult[freqIndex].ts < initStateResult[stateIndex].ts) { + newfreqVal = initFreqResult[freqIndex].value; + newBeginNs = initFreqResult[freqIndex].ts; + newfreqId = initFreqResult[freqIndex].filterId; + freqIndex++; + } else if (initFreqResult[freqIndex].ts > initStateResult[stateIndex].ts) { + newStateVal = initStateResult[stateIndex].value; + newBeginNs = initStateResult[stateIndex].ts; + stateIndex++; + } else { + newStateVal = initStateResult[stateIndex].value; + newfreqVal = initFreqResult[freqIndex].value; + newfreqId = initFreqResult[freqIndex].filterId; + newBeginNs = initStateResult[stateIndex].ts; + freqIndex++; + stateIndex++; + } + //取state = 0的情况并根据频率去加等赋值 + if (stateVal == 0) { + busyTime = newBeginNs - beginNs; + if (sampleMap.has(freqId + '-' + freqVal)) { + let obj = sampleMap.get(freqId + '-' + freqVal); + obj.busyTime += busyTime + } + } + beginNs = newBeginNs; + freqId = newfreqId; + freqVal = newfreqVal; + stateVal = newStateVal + } +} + +self.onmessage = (e: MessageEvent) => { + let leftStartNs = e.data.frqSampleParam.leftNs + e.data.frqSampleParam.recordStartNs; + let rightEndNs = e.data.frqSampleParam.rightNs + e.data.frqSampleParam.recordStartNs; + e.data.cpuFiliterOrder.forEach((a: number) => { + getBusyTime( + e.data.result.filter((f: any) => f.cpu == a), + e.data.res.filter((f: any) => f.cpu == a), + e.data.sampleMap, + leftStartNs, + rightEndNs + ) + }) + e.data.sampleMap.forEach((a: any) => { + a.busyTime = parseFloat((a.busyTime / 1000000.0).toFixed(6)) + }) + + self.postMessage(e.data.sampleMap) +} \ No newline at end of file