diff --git a/ide/src/trace/bean/GpufreqBean.ts b/ide/src/trace/bean/GpufreqBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..a633f24b6755fec0207566dacdef22c273dbf255 --- /dev/null +++ b/ide/src/trace/bean/GpufreqBean.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 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. + */ +export class GpuCountBean { + filterId: string = ''; + freq: string = ''; + count: string = ''; + value: string = ''; + ts: string = ''; + startNS: string = ''; + dur: string = ''; + endTime: string = ''; + thread: string = ''; + parentIndex: number = 0; + level?: number = 0; + name?: string = ''; + constructor(filterId: string, freq: string, count: string, value: string, ts: string, dur: string, startNS: string, endTime: string, thread: string, parentIndex: number) { + this.filterId = filterId; + this.freq = freq; + this.count = count; + this.value = value; + this.ts = ts; + this.dur = dur; + this.startNS = startNS; + this.endTime = endTime; + this.thread = thread; + this.parentIndex = parentIndex + } +}; +export class SearchGpuFuncBean { + funName: string | undefined; + startTime: number = 0; + dur: number | undefined; + endTime: number = 0; + depth: number | undefined; + threadName: string | undefined; + pid: number | undefined; +}; +export class TreeDataBean { + thread?: string = ''; + count: string = ''; + freq?: string = ''; + gpufreq?: string = ''; + dur: string = ''; + value?: string = ''; + percent?: string = ''; + children: TreeDataBean[] = []; + status?: boolean = false; + ts?: string = ''; + startTime?: string = ''; + startNS?: string = ''; + level?: number; + cycle?: number; +}; \ No newline at end of file diff --git a/ide/src/trace/component/trace/base/TraceSheetConfig.ts b/ide/src/trace/component/trace/base/TraceSheetConfig.ts index 52a5a2becd3abcf2ae99123b6b4142d615f3de6e..a80d778afe43affd060bb27d485b76062abef8bb 100644 --- a/ide/src/trace/component/trace/base/TraceSheetConfig.ts +++ b/ide/src/trace/component/trace/base/TraceSheetConfig.ts @@ -122,6 +122,8 @@ import { TabPaneFreqUsage } from '../sheet/frequsage/TabPaneFreqUsage'; import { TabPaneFreqDataCut } from '../sheet/frequsage/TabPaneFreqDataCut'; import { TabPaneHisysEvents } from '../sheet/hisysevent/TabPaneHisysEvents'; import { TabPaneHiSysEventSummary } from '../sheet/hisysevent/TabPaneHiSysEventSummary'; +import { TabPaneGpufreq } from '../sheet/gpufreq/tabPaneGpufreqUsage'; +import { TabPaneGpufreqDataCut } from '../sheet/gpufreq/tabPaneGpufreqDataCut'; export let tabConfig: any = { 'current-selection': { @@ -650,4 +652,14 @@ export let tabConfig: any = { type: TabPaneHiSysEventSummary, require: (param: SelectionParam) => param.hiSysEvents.length > 0, }, + 'tabpane-gpufreq': { + title: 'Gpufreq Usage', + type: TabPaneGpufreq, + require: (param: SelectionParam) => param.clockMapData.size > 0 && param.clockMapData.size < 2, + }, + 'tabpane-freqDataCut': { + title: 'Gpufreq DataCut', + type: TabPaneGpufreqDataCut, + require: (param: SelectionParam) => param.clockMapData.size > 0 && param.clockMapData.size < 2, + } }; diff --git a/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqDataCut.ts b/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqDataCut.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5f10bae10f1b20542d1a018b82779ffdeae855b --- /dev/null +++ b/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqDataCut.ts @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2023 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. + */ +import { BaseElement, element } from '../../../../../base-ui/BaseElement'; +import { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; +import { SelectionParam } from '../../../../bean/BoxSelection'; +import { getGpufreqData, getGpufreqDataCut } from '../../../../database/SqlLite'; +import { resizeObserver } from '../SheetUtils'; +import { SpSegmentationChart } from '../../../chart/SpSegmentationChart'; +import { GpuCountBean, TreeDataBean, type SearchGpuFuncBean } from '../../../../bean/GpufreqBean' + +@element('tabpane-gpufreqdatacut') +export class TabPaneGpufreqDataCut extends BaseElement { + private threadStatesTbl: LitTable | null | undefined; + private currentSelectionParam: SelectionParam | undefined; + private _single: Element | null | undefined; + private _loop: Element | null | undefined; + private _threadId: HTMLInputElement | null | undefined; + private _threadFunc: HTMLInputElement | null | undefined; + private threadIdValue: string = ''; + private threadFuncName: string = ''; + private initData: Array = []; + + set data(threadStatesParam: SelectionParam) { + if (this.currentSelectionParam === threadStatesParam) { + return; + } else { + this._threadId!.value = ""; + this._threadFunc!.value = ""; + }; + this.currentSelectionParam = threadStatesParam; + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = true; + this.getGpufreqData(threadStatesParam.leftNs, threadStatesParam.rightNs, false).then((result) => { + if (result !== null && result.length > 0) { + let resultList: Array = JSON.parse(JSON.stringify(result)); + if (result.length === 1) { + resultList[0].dur = String(threadStatesParam.rightNs - threadStatesParam.leftNs); + resultList[0].count = String(Number(resultList[0].dur) * Number(resultList[0].value)); + } else { + resultList[0].dur = String(Number(resultList[1].startNS) - threadStatesParam.leftNs); + resultList[0].count = String(Number(resultList[0].dur) * Number(resultList[0].value)); + + resultList[resultList.length - 1].dur = String(threadStatesParam.rightNs - Number(resultList[resultList.length - 1].startNS)); + resultList[resultList.length - 1].count = String(Number(resultList[resultList.length - 1].dur) * Number(resultList[resultList.length - 1].value)); + }; + + this.initData = resultList; + this.threadStatesTbl!.loading = false; + + } else { + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = false; + }; + + }); + }; + + initElements(): void { + this.threadStatesTbl = this.shadowRoot?.querySelector('#tb-gpufreq-percent'); + this._single = this.shadowRoot?.querySelector('#single'); + this._loop = this.shadowRoot?.querySelector('#loop'); + this._threadId = this.shadowRoot?.querySelector('#dataCutThreadId'); + this._threadFunc = this.shadowRoot?.querySelector('#dataCutThreadFunc'); + this.threadIdValue = this._threadId!.value.trim(); + this.threadFuncName = this._threadFunc!.value.trim(); + const originalThreadIdStyle: string = this._threadId!.style.border; + const originalThreadFuncStyle: string = this._threadId!.style.border; + const originalThreadIdPlaceholder: string = String(this._threadId!.getAttribute('placeholder')); + const originalThreadFuncPlaceholder: string = String(this._threadId!.getAttribute('placeholder')); + //点击single + this._single?.addEventListener('click', (e) => { + this.threadIdValue = this._threadId!.value.trim(); + this.threadFuncName = this._threadFunc!.value.trim(); + this.threadStatesTbl!.loading = true; + this.validationFun( + this.threadIdValue, this.threadFuncName, originalThreadIdStyle, + originalThreadFuncStyle, originalThreadIdPlaceholder, originalThreadFuncPlaceholder, 'single'); + }); + //点击loop + this._loop?.addEventListener('click', (e) => { + this.threadIdValue = this._threadId!.value.trim(); + this.threadFuncName = this._threadFunc!.value.trim(); + this.threadStatesTbl!.loading = true; + this.validationFun( + this.threadIdValue, this.threadFuncName, originalThreadIdStyle, + originalThreadFuncStyle, originalThreadIdPlaceholder, + originalThreadFuncPlaceholder, 'loop'); + }); + this.threadStatesTbl?.addEventListener('row-click', (event: Event) => { + // @ts-ignore + if (event.detail.level === 2 && event.detail.thread.includes('cycle')) { + // @ts-ignore + SpSegmentationChart.tabHover('GPU-FREQ', true, event.detail.data.cycle); + }; + }); + this._threadId?.addEventListener('change', function () { + if (this.value.trim() !== '') { + this.style.border = originalThreadIdStyle; + this.setAttribute('placeholder', originalThreadIdPlaceholder); + }; + }); + this._threadFunc?.addEventListener('change', function () { + if (this.value.trim() !== '') { + this.style.border = originalThreadFuncStyle; + this.setAttribute('placeholder', originalThreadFuncPlaceholder); + }; + }); + }; + connectedCallback(): void { + super.connectedCallback(); + resizeObserver(this.parentElement!, this.threadStatesTbl!); + }; + + initHtml(): string { + return ` +
+ + +
+ + +
+
+ + + + + + + + + + + + + + `; + }; + + private validationFun( + threadIdValue: string, + threadFuncName: string, + originalThreadIdStyle: string, + originalThreadFuncStyle: string, + originalThreadIdPlaceholder: string, + originalThreadFuncPlaceholder: string, + fun: string): void { + if (threadIdValue === '') { + this.threadStatesTbl!.loading = false; + this._threadId!.style.border = '1px solid rgb(255,0,0)'; + this._threadId!.setAttribute('placeholder', 'Please input thread id'); + this.threadStatesTbl!.recycleDataSource = []; + } else if (threadFuncName === '') { + this.threadStatesTbl!.loading = false; + this._threadFunc!.style.border = '1px solid rgb(255,0,0)'; + this._threadFunc!.setAttribute('placeholder', 'Please input function name'); + this.threadStatesTbl!.recycleDataSource = []; + } else { + this._threadId!.style.border = originalThreadIdStyle; + this._threadFunc!.style.border = originalThreadFuncStyle; + this._threadId!.setAttribute('placeholder', originalThreadIdPlaceholder); + this._threadFunc!.setAttribute('placeholder', originalThreadFuncPlaceholder); + if (fun === 'single') { + this.getGpufreqDataCut( + threadIdValue, + threadFuncName, + this.currentSelectionParam!.leftNs, + this.currentSelectionParam!.rightNs, + true, false) + .then((result: Array) => { + let _initData = JSON.parse(JSON.stringify(this.initData)); + this.handleDataCut(_initData, result); + }); + }; + if (fun === 'loop') { + this.getGpufreqDataCut( + threadIdValue, + threadFuncName, + this.currentSelectionParam!.leftNs, + this.currentSelectionParam!.rightNs, + false, true) + .then((result: Array) => { + let _initData = JSON.parse(JSON.stringify(this.initData)); + this.handleDataCut(_initData, result); + }); + }; + }; + }; + + private handleDataCut(initData: Array, dataCut: Array): void { + if (initData.length > 0 && dataCut.length > 0) { + this.getGpufreqData(this.currentSelectionParam!.leftNs, this.currentSelectionParam!.rightNs, true) + .then((result: Array) => { + if (result.length > 0 && dataCut.length > 0) { + this.filterData(initData, dataCut, result); + } else { + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = false; + }; + + }); + } else { + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = false; + SpSegmentationChart.setChartData('GPU-FREQ', []); + } + + }; + + async getGpufreqData(leftNs: number, rightNs: number, isTrue: boolean): Promise> { + let result: Array = await getGpufreqData(leftNs, rightNs, isTrue) + return result; + }; + + async getGpufreqDataCut(tIds: string, funcName: string, leftNS: number, rightNS: number, single: boolean, loop: boolean): Promise> { + let result: Array = await getGpufreqDataCut(tIds, funcName, leftNS, rightNS, single, loop) + return result; + }; + + private filterData(initData: Array, dataCut: Array, result: Array): void { + let finalGpufreqData: Array = new Array(); + let earliest: number = Number(result[0].startNS); + let _dataCut: Array = dataCut.filter(i => i.startTime >= earliest); + let _lastList: Array = []; + for (let i = 0; i < _dataCut.length; i++) { + let e: SearchGpuFuncBean = _dataCut[i]; + for (let j of initData) { + _lastList.push(...this.segmentationData(j, e, i)); + }; + }; + let tree: TreeDataBean = this.createTree(_lastList); + finalGpufreqData.push(tree); + this.threadStatesTbl!.recycleDataSource = finalGpufreqData; + this.threadStatesTbl!.loading = false; + this.theadClick(finalGpufreqData); + }; + + private segmentationData(j: GpuCountBean, e: SearchGpuFuncBean, i: number): Array { + let lastList: Array = []; + if (e.startTime >= Number(j.startNS) && e.startTime <= Number(j.endTime)) { + if (e.endTime <= Number(j.endTime)) { + lastList.push(new GpuCountBean( + j.filterId, j.freq, + String((e.endTime - e.startTime) * Number(j.value)), + j.value, + String(e.startTime + this.currentSelectionParam!.recordStartNs), + String(e.endTime - e.startTime), + String(e.startTime), + String(e.endTime), + j.thread, i)); + } else { + lastList.push(new GpuCountBean( + j.filterId, j.freq, + String((Number(j.endTime) - e.startTime) * Number(j.value)), + j.value, + String(e.startTime + this.currentSelectionParam!.recordStartNs), + String(Number(j.endTime) - e.startTime), + String(e.startTime), + String(j.endTime), + j.thread, i)); + }; + } else if (e.startTime <= Number(j.startNS) && Number(j.endTime) <= e.endTime) { + lastList.push(new GpuCountBean( + j.filterId, j.freq, + String((Number(j.endTime) - Number(j.startNS)) * Number(j.value)), + j.value, + String(Number(j.startNS) + this.currentSelectionParam!.recordStartNs), + String(Number(j.endTime) - Number(j.startNS)), + String(j.startNS), + String(j.endTime), + j.thread, i)); + } else if (Number(j.startNS) <= e.endTime && e.endTime <= Number(j.endTime)) { + lastList.push(new GpuCountBean( + j.filterId, j.freq, + String((e.endTime - Number(j.startNS)) * Number(j.value)), + j.value, + String(Number(j.startNS) + this.currentSelectionParam!.recordStartNs), + String(e.endTime - Number(j.startNS)), + String(j.startNS), + String(e.endTime), + j.thread, i)); + }; + return lastList; + }; + + private createTree(data: Array): TreeDataBean { + if (data.length > 0) { + const root = { + thread: 'gpufreq Frequency', + count: '0', + freq: '', + dur: '0', + percent: '100', + level: 1, + children: [], + }; + const valueMap: { [parentIndex: string]: TreeDataBean } = {}; + data.forEach((item: GpuCountBean) => { + let parentIndex: number = item.parentIndex !== undefined ? item.parentIndex : 0; + let freq: string = item.freq; + const UNIT: number = 1000000; + const KUNIT: number = 1000000000000; + let _dur: number = Number(item.dur); + let _count: number = Number(item.count); + let _freq: number = Number(item.freq) + item.thread = `${item.thread} Frequency`; + item.level = 4; + item.dur = (_dur / UNIT).toFixed(3); + item.count = (_count / KUNIT).toFixed(3); + item.freq = _freq.toFixed(3); + this.updateValueMap(item, parentIndex, freq, valueMap, UNIT); + }); + Object.values(valueMap).forEach((node: TreeDataBean) => { + const parentNode: TreeDataBean = valueMap[Number(node.value) - 1]; + if (parentNode) { + this.updateChildNode(node, parentNode); + } else { + this.updateRootNode(node, root); + }; + }); + // 移除 key 值 + root.children.forEach((item: TreeDataBean) => { + item.children = Object.values(item.children); + }); + this.calculatePercent(root, root); + SpSegmentationChart.setChartData('GPU-FREQ', root.children); + return root; + } else { + return new TreeDataBean(); + } + }; + + private updateValueMap(item: GpuCountBean, parentIndex: number, freq: string, valueMap: { [parentIndex: string]: TreeDataBean }, UNIT: number): void { + if (!valueMap[parentIndex]) { + valueMap[parentIndex] = { + thread: `cycle ${parentIndex + 1} ${item.thread}`, + count: item.count, + dur: item.dur, + ts: item.ts, + startTime: (Number(item.startNS) / UNIT).toFixed(3), + startNS: item.startNS, + percent: '100', + level: 2, + cycle: parentIndex + 1, + children: [], + }; + } else { + let fdur: number = Number(valueMap[parentIndex].dur); + let fcount: number = Number(valueMap[parentIndex].count); + let idur: number = Number(item.dur); + let icount: number = Number(item.count); + fdur += idur; + valueMap[parentIndex].dur = fdur.toFixed(3); + fcount += icount; + valueMap[parentIndex].count = fcount.toFixed(3); + }; + if (!valueMap[parentIndex].children[Number(freq)]) { + valueMap[parentIndex].children[Number(freq)] = { + thread: item.thread, + count: item.count, + gpufreq: item.freq, + dur: item.dur, + percent: '100', + level: 3, + children: [], + }; + } else { + let zdur: number = Number(valueMap[parentIndex].children[Number(freq)].dur); + let zcount: number = Number(valueMap[parentIndex].children[Number(freq)].count); + let idur: number = Number(item.dur); + let icount: number = Number(item.count); + zdur += idur; + valueMap[parentIndex].children[Number(freq)].dur = zdur.toFixed(3); + zcount += icount; + valueMap[parentIndex].children[Number(freq)].count = zcount.toFixed(3); + }; + valueMap[parentIndex].children[Number(freq)].children.push(item as unknown as TreeDataBean); + }; + + private updateChildNode(node: TreeDataBean, parentNode: TreeDataBean): void { + parentNode.children.push(node); + let pdur: number = Number(parentNode.dur); + let pcount: number = Number(parentNode.count); + let ndur: number = Number(node.dur); + let ncount: number = Number(node.count); + pdur += ndur; + parentNode.dur = pdur.toFixed(3); + pcount += ncount; + parentNode.count += pcount.toFixed(3); + }; + + private updateRootNode(node: TreeDataBean, root: TreeDataBean): void { + root.children.push(node); + let rdur: number = Number(root.dur); + let rcount: number = Number(root.count); + let ndur: number = Number(node.dur); + let ncount: number = Number(node.count); + rdur += ndur; + root.dur = rdur.toFixed(3); + rcount += ncount; + root.count = rcount.toFixed(3); + }; + + private calculatePercent(node: TreeDataBean, root: TreeDataBean): void { + node.percent = (Number(node.count) / Number(root.count) * 100).toFixed(2); + + if (node.children && node.children.length > 0) { + node.children.forEach((childNode) => this.calculatePercent(childNode, root)); + } else { + return; + }; + }; + + private theadClick(data: Array): void { + let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); + + if (labels) { + for (let i = 0; i < labels.length; i++) { + let label = labels[i].innerHTML; + labels[i].addEventListener('click', (e) => { + + if (label.includes('Thread') && i === 0) { + this.threadStatesTbl!.setStatus(data, false); + this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); + + } else if (label.includes('Cycle') && i === 1) { + for (let item of data) { + item.status = true; + if (item.children !== undefined && item.children.length > 0) { + this.threadStatesTbl!.setStatus(item.children, false); + }; + }; + this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); + + } else if (label.includes('Freq') && i === 2) { + for (let item of data) { + item.status = true; + for (let e of item.children ? item.children : []) { + e.status = true; + if (e.children !== undefined && e.children.length > 0) { + this.threadStatesTbl!.setStatus(e.children, false, 0); + }; + }; + }; + + this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); + + }; + }); + }; + }; + + }; + +} \ No newline at end of file diff --git a/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqUsage.ts b/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqUsage.ts new file mode 100644 index 0000000000000000000000000000000000000000..db3b7bd0ba5344c1c9f69ade0b4e6d0b096de532 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/gpufreq/tabPaneGpufreqUsage.ts @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2023 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. + */ + +import { BaseElement, element } from '../../../../../base-ui/BaseElement'; +import { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; +import { type SelectionParam } from '../../../../bean/BoxSelection'; +import { getGpufreqData } from '../../../../database/SqlLite'; +import { resizeObserver } from '../SheetUtils'; +import { type GpuCountBean, TreeDataBean } from '../../../../bean/GpufreqBean' + +@element('tabpane-gpufreq') +export class TabPaneGpufreq extends BaseElement { + private threadStatesTbl: LitTable | null | undefined; + private currentSelectionParam: SelectionParam | undefined; + + set data(clockCounterValue: SelectionParam) { + let finalGpufreqData: Array = []; + if (this.currentSelectionParam === clockCounterValue) { + return; + }; + this.currentSelectionParam = clockCounterValue; + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = true; + getGpufreqData(clockCounterValue.leftNs, clockCounterValue.rightNs, false).then((result: Array): void => { + if (result !== null && result.length > 0) { + let resultList: Array = JSON.parse(JSON.stringify(result)); + if (result.length === 1) { + resultList[0].dur = String(clockCounterValue.rightNs - clockCounterValue.leftNs); + resultList[0].count = String(Number(resultList[0].dur) * Number(resultList[0].value)); + } else { + resultList[0].dur = String(Number(resultList[1].startNS) - clockCounterValue.leftNs); + resultList[0].count = String(Number(resultList[0].dur) * Number(resultList[0].value)); + + resultList[resultList.length - 1].dur = String(clockCounterValue.rightNs - Number(resultList[resultList.length - 1].startNS)); + resultList[resultList.length - 1].count = String(Number(resultList[resultList.length - 1].dur) * Number(resultList[resultList.length - 1].value)); + }; + let tree: TreeDataBean = this.createTree(resultList); + finalGpufreqData.push(tree); + this.threadStatesTbl!.recycleDataSource = finalGpufreqData; + this.threadStatesTbl!.loading = false; + this.theadClick(finalGpufreqData); + } else { + this.threadStatesTbl!.recycleDataSource = []; + this.threadStatesTbl!.loading = false; + }; + + }); + }; + + initElements(): void { + this.threadStatesTbl = this.shadowRoot?.querySelector('#tb-gpufreq-percent'); + }; + + connectedCallback(): void { + super.connectedCallback(); + resizeObserver(this.parentElement!, this.threadStatesTbl!); + }; + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + }; + + private createTree(data: Array): TreeDataBean { + if (data.length > 0) { + const root = { + thread: 'gpufreq Frequency', + count: '0', + freq: '', + dur: '0', + percent: '100', + children: [], + }; + + const valueMap: { [freq: string]: TreeDataBean } = {}; + data.forEach((item: GpuCountBean) => { + let freq: string = item.freq; + let UNIT: number = 1000000; + const KUNIT: number = 1000000000000; + let _dur: number = Number(item.dur); + let _count: number = Number(item.count); + let _freq: number = Number(item.freq); + item.dur = (_dur / UNIT).toFixed(3); + item.count = (_count / KUNIT).toFixed(3); + item.freq = _freq.toFixed(3); + item.thread = `${item.thread} Frequency`; + this.updateValueMap(item, freq, valueMap); + }); + Object.values(valueMap).forEach((node: TreeDataBean) => { + const parentNode: TreeDataBean = valueMap[Number(node.value) - 1]; + if (parentNode) { + this.updateChildNode(node, parentNode); + } else { + this.updateRootNode(node, root); + }; + }); + + this.calculatePercent(root, root); + + return root; + + }; + return new TreeDataBean(); + }; + + private updateValueMap(item: GpuCountBean, freq: string, valueMap: { [freq: string]: TreeDataBean }): void { + if (!valueMap[freq]) { + valueMap[freq] = { + thread: 'gpufreq Frequency', + count: item.count, + gpufreq: item.freq, + dur: item.dur, + percent: '100', + children: [], + }; + } else { + let fdur: number = Number(valueMap[freq].dur); + let fcount: number = Number(valueMap[freq].count); + let idur: number = Number(item.dur); + let icount: number = Number(item.count); + fdur += idur; + valueMap[freq].dur = fdur.toFixed(3); + fcount += icount; + valueMap[freq].count = fcount.toFixed(3); + }; + valueMap[freq].children.push(item as unknown as TreeDataBean); + }; + + private updateChildNode(node: TreeDataBean, parentNode: TreeDataBean): void { + parentNode.children.push(node); + let pdur: number = Number(parentNode.dur); + let pcount: number = Number(parentNode.count); + let ndur: number = Number(node.dur); + let ncount: number = Number(node.count); + pdur += ndur; + parentNode.dur = pdur.toFixed(3); + pcount += ncount; + parentNode.count = pcount.toFixed(3); + }; + + private updateRootNode(node: TreeDataBean, root: TreeDataBean): void { + root.children.push(node); + let rdur: number = Number(root.dur); + let rcount: number = Number(root.count); + let ndur: number = Number(node.dur); + let ncount: number = Number(node.count); + rdur += ndur; + root.dur = rdur.toFixed(3); + rcount += ncount; + root.count = rcount.toFixed(3); + }; + + private calculatePercent(node: TreeDataBean, root: TreeDataBean): void { + node.percent = (Number(node.count) / Number(root.count) * 100).toFixed(2); + + if (node.children && node.children.length > 0) { + node.children.forEach((childNode) => this.calculatePercent(childNode, root)); + } else { + return; + }; + }; + + private theadClick(data: Array): void { + let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); + + if (labels) { + for (let i = 0; i < labels.length; i++) { + let label = labels[i].innerHTML; + labels[i].addEventListener('click', (e) => { + + if (label.includes('Thread') && i === 0) { + this.threadStatesTbl!.setStatus(data, false); + this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); + + } else if (label.includes('Freq') && i === 1) { + + for (let item of data) { + item.status = true; + if (item.children !== undefined && item.children.length > 0) { + this.threadStatesTbl!.setStatus(item.children, false); + }; + }; + this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); + + }; + }); + }; + }; + }; +} \ No newline at end of file diff --git a/ide/src/trace/database/SqlLite.ts b/ide/src/trace/database/SqlLite.ts index 28c4e6a7162b7517bc1a48cbc4542b2bd80b14ac..7c733df0b0623fc614c205249c22e7dcf749559c 100644 --- a/ide/src/trace/database/SqlLite.ts +++ b/ide/src/trace/database/SqlLite.ts @@ -83,6 +83,7 @@ import { type MemoryConfig } from '../bean/MemoryConfig'; import { LogStruct } from './ui-worker/ProcedureWorkerLog'; import { HiSysEventStruct } from './ui-worker/ProcedureWorkerHiSysEvent'; import { KeyPathStruct } from '../bean/KeyPathStruct'; +import { GpuCountBean, SearchGpuFuncBean } from '../bean/GpufreqBean'; class DataWorkerThread { taskMap: any = {}; @@ -5887,3 +5888,110 @@ export const queryCpuKeyPathData = (threads: Array): Promise> => { + let queryCondition: string = ''; + if (!earliest) { + queryCondition += ` where not ((s.ts - r.start_ts + ifnull(s.dur,0) < ${leftNS}) or (s.ts - r.start_ts > ${rightNS}))` + } + return query( + 'getGpufreqData', + ` + with state as + (select + name, + filter_id, + ts, + endts, + endts-ts as dur, + type, + value + from + (select + measure.filter_id, + clock_event_filter.name, + measure.ts, + lead(ts, 1, null) over( order by measure.ts) endts, + measure.type, + measure.value + from + clock_event_filter, + trace_range + left join + measure + where + clock_event_filter.name = 'gpufreq' + and + clock_event_filter.type = 'clock_set_rate' + and + clock_event_filter.id = measure.filter_id + order by measure.ts) + where + endts is not null + ) + select + s.name as thread, + s.filter_id as filterId, + s.value/1000000 as freq, + s.value*s.dur as count, + s.value, + s.ts, + s.ts-r.start_ts as startNS, + s.dur, + s.endts- r.start_ts as endTime + from + state s, + trace_range r + ${queryCondition} + order by ts + `, + { $leftNS: leftNS, $rightNS: rightNS } + ); +} + +export const getGpufreqDataCut = (tIds: string, funcName: string, leftNS: number, rightNS: number, single: boolean, loop: boolean): Promise> => { + let queryCondition: string = ''; + if (single) { + queryCondition += `select s.funName,s.startTime,s.dur,s.startTime+s.dur as endTime,s.depth,s.tid,s.threadName,s.pid from state s + where endTime between ${leftNS} and ${rightNS}`; + } + if (loop) { + queryCondition += `select s.funName,s.startTime,s.loopEndTime-s.startTime as dur,s.loopEndTime as endTime,s.depth,s.tid,s.threadName,s.pid from state s + where endTime between ${leftNS} and ${rightNS} `; + } + return query( + 'getGpufreqDataCut', + ` + with state as + (select + * + from + (select + c.name as funName, + c.ts - r.start_ts as startTime, + c.dur, + lead(c.ts - r.start_ts, 1, null) over( order by c.ts - r.start_ts) loopEndTime, + c.depth, + t.tid, + t.name as threadName, + p.pid + from + callstack c + left join + thread t on c.callid = t.id + left join + process p on t.ipid = p.id + left join + trace_range r + where + c.name like '%${funcName}%' + and + tid = '${tIds}' + and + startTime between ${leftNS} and ${rightNS})) + ${queryCondition} + `, + { $search: funcName } + ); +} +