From 87de7efca788ad608adc23bb3d659077db4c56c3 Mon Sep 17 00:00:00 2001 From: zhangyan Date: Thu, 14 Dec 2023 20:04:57 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=B8=ADRunning=E5=88=87=E5=89=B2=E7=9A=84?= =?UTF-8?q?=E6=AC=A1=E6=95=B0=EF=BC=8C=E7=BB=98=E5=88=B6=E6=9F=B1=E7=8A=B6?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangyan --- .../base-ui/chart/column/LitChartColumn.ts | 64 +- .../chart/column/LitChartColumnConfig.ts | 14 +- ide/src/trace/bean/SchedSwitchStruet.ts | 80 ++ .../component/trace/base/TraceSheetConfig.ts | 6 + .../sheet/schedswitch/TabPaneSchedSwitch.ts | 791 ++++++++++++++++++ ide/src/trace/database/SqlLite.ts | 84 ++ 6 files changed, 1002 insertions(+), 37 deletions(-) create mode 100644 ide/src/trace/bean/SchedSwitchStruet.ts create mode 100644 ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts diff --git a/ide/src/base-ui/chart/column/LitChartColumn.ts b/ide/src/base-ui/chart/column/LitChartColumn.ts index acf163198..9f50322ae 100644 --- a/ide/src/base-ui/chart/column/LitChartColumn.ts +++ b/ide/src/base-ui/chart/column/LitChartColumn.ts @@ -207,40 +207,42 @@ export class LitChartColumn extends BaseElement { for (let i = 0; i <= 5; i++) { this.rowLines.push({ y: gap * i, - label: `${getProbablyTime(maxValue - valGap * i)}`, + label: this.litChartColumnCfg.removeUnit === true ? `${maxValue - valGap * i}` : `${getProbablyTime(maxValue - valGap * i)}`, }); } - this.litChartColumnCfg?.data - .sort((a, b) => b[this.litChartColumnCfg!.yField] - a[this.litChartColumnCfg!.yField]) - .forEach((litChartColumnItem, litChartColumnIndex, array) => { - this.data.push({ - color: this.litChartColumnCfg!.color(litChartColumnItem), - obj: litChartColumnItem, - root: true, - xLabel: litChartColumnItem[this.litChartColumnCfg!.xField], - yLabel: litChartColumnItem[this.litChartColumnCfg!.yField], - bgFrame: { - x: this.offset!.x! + partWidth * litChartColumnIndex, - y: 0, - w: partWidth, - h: partHeight, - }, - centerX: this.offset!.x! + partWidth * litChartColumnIndex + partWidth / 2, - centerY: - partHeight - - (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue + - (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue / 2, - frame: { - x: this.offset!.x! + partWidth * litChartColumnIndex + partWidth / 6, - y: partHeight - (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue, - w: partWidth - partWidth / 3, - h: (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue, - }, - height: 0, - heightStep: Math.ceil((litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue / 60), - process: true, - }); + if (!this.litChartColumnCfg.notSort) { + this.litChartColumnCfg?.data + .sort((a, b) => b[this.litChartColumnCfg!.yField] - a[this.litChartColumnCfg!.yField]); + } + this.litChartColumnCfg?.data.forEach((litChartColumnItem, litChartColumnIndex, array) => { + this.data.push({ + color: this.litChartColumnCfg!.color(litChartColumnItem), + obj: litChartColumnItem, + root: true, + xLabel: litChartColumnItem[this.litChartColumnCfg!.xField], + yLabel: litChartColumnItem[this.litChartColumnCfg!.yField], + bgFrame: { + x: this.offset!.x! + partWidth * litChartColumnIndex, + y: 0, + w: partWidth, + h: partHeight, + }, + centerX: this.offset!.x! + partWidth * litChartColumnIndex + partWidth / 2, + centerY: + partHeight - + (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue + + (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue / 2, + frame: { + x: this.offset!.x! + partWidth * litChartColumnIndex + partWidth / 6, + y: partHeight - (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue, + w: partWidth - partWidth / 3, + h: (litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue, + }, + height: 0, + heightStep: Math.ceil((litChartColumnItem[this.litChartColumnCfg!.yField] * partHeight) / maxValue / 60), + process: true, }); + }); } else { let reduceGroup = this.litChartColumnCfg.data.reduce((pre, current, index, arr) => { (pre[current[this.litChartColumnCfg!.xField]] = pre[current[this.litChartColumnCfg!.xField]] || []).push( diff --git a/ide/src/base-ui/chart/column/LitChartColumnConfig.ts b/ide/src/base-ui/chart/column/LitChartColumnConfig.ts index b508e8278..0b3283a39 100644 --- a/ide/src/base-ui/chart/column/LitChartColumnConfig.ts +++ b/ide/src/base-ui/chart/column/LitChartColumnConfig.ts @@ -19,14 +19,16 @@ export interface LitChartColumnConfig { xField: string; yField: string; seriesField: string; + notSort?: boolean; + removeUnit?: boolean; color: (a: any) => string; tip: ((a: any) => string) | undefined; hoverHandler?: (no: number) => void; label: - | { - offset: number; - content: (it: any) => string; - } - | undefined - | null; + | { + offset: number; + content: (it: any) => string; + } + | undefined + | null; } diff --git a/ide/src/trace/bean/SchedSwitchStruet.ts b/ide/src/trace/bean/SchedSwitchStruet.ts new file mode 100644 index 000000000..6182c5128 --- /dev/null +++ b/ide/src/trace/bean/SchedSwitchStruet.ts @@ -0,0 +1,80 @@ +/* + * 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 InitThreadConfig { + dur: number = 0; + endTs: number = 0; + id: number = -1; + pid: number = -1; + state: string = ''; + tid: number = -1; + ts: number = -1 + type: string = '' +} + +export class TreeSwitchConfig { + count: number = 0; + cycleNum: number = 1; + duration!: number | string | undefined; + isHover?: boolean = false; + isSelected?: boolean = false; + cycle?: number = 0; + level: string = ''; + pid: number = -1; + process: string | undefined; + state?: string = ''; + status?: boolean = false; + thread: string | undefined; + tid: number = -1; + title: string = ''; + ts?: string = ''; + cycleStartTime!: number | string | undefined; + children: Array = []; +} + +export class HistogramSourceConfig { + average: number = 0; + color: string = ''; + count: number = 0; + cycleNum: number = 0; + isHover: boolean = false; + size: string = '' +} + +export class ThreadInitConfig { + dur: number = 0; + endTs: number = 0; + id: number = 0; + pid: number = -1; + state?: string = ''; + tid: number = -1; + ts: number = -1; + type: string = '' +} + +export class SchedThreadCutConfig { + cycleEndTime: number = 0; + cycleStartTime: number = 0; + funId: number = 0; + name: string = '' + pid: number = -1; + runningCnt: number = 0; + state: string = ''; + tid: number = -1; + process?: string = ''; + thread?: string = ''; + dur?: number = 0; + leftNS?: number = 0 +} \ 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 52a5a2bec..cf40be007 100644 --- a/ide/src/trace/component/trace/base/TraceSheetConfig.ts +++ b/ide/src/trace/component/trace/base/TraceSheetConfig.ts @@ -122,6 +122,7 @@ 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 { TabPaneSchedSwitch } from '../sheet/schedswitch/TabPaneSchedSwitch'; export let tabConfig: any = { 'current-selection': { @@ -650,4 +651,9 @@ export let tabConfig: any = { type: TabPaneHiSysEventSummary, require: (param: SelectionParam) => param.hiSysEvents.length > 0, }, + 'tabpane-schedswitch': { + title: 'Sched Switch', + type: TabPaneSchedSwitch, + require: (param: SelectionParam) => param.threadIds.length > 0, + } }; diff --git a/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts b/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts new file mode 100644 index 000000000..ab78aa9f5 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts @@ -0,0 +1,791 @@ +/* + * 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 { LitButton } from '../../../../../base-ui/button/LitButton.js'; +import { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; +import { querySchedThreadStates, querySingleCutData, queryLoopCutData } from '../../../../database/SqlLite'; +import { Utils } from '../../base/Utils'; +import { resizeObserver } from '../SheetUtils'; +import { LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn'; +import { + type TreeSwitchConfig, + InitThreadConfig, + HistogramSourceConfig, + ThreadInitConfig, + SchedThreadCutConfig +} from '../../../../bean/SchedSwitchStruet'; +// import { SpSegmentationChart } from '../../../../../trace/component/chart/SpSegmentationChart' + + +@element('tabpane-schedswitch') +export class TabPaneSchedSwitch extends BaseElement { + private schedSwitchTbl: LitTable | null | undefined; + private threadQueryDIV: Element | null | undefined; + private rightDIV: HTMLDivElement | null | undefined; + private threadIdInput: HTMLInputElement | null | undefined; + private funcNameInput: HTMLInputElement | null | undefined; + private singleBtn: LitButton | null | undefined; + private loopBtn: LitButton | null | undefined; + private cycleALeftInput: HTMLInputElement | null | undefined; + private cycleARightInput: HTMLInputElement | null | undefined; + private cycleBLeftInput: HTMLInputElement | null | undefined; + private cycleBRightInput: HTMLInputElement | null | undefined; + private queryButton: LitButton | null | undefined; + private threadFlag: string = ''; + private selectionParam: SelectionParam | undefined; + private canvansName: HTMLDivElement | null | undefined; + private singleSourceData: Array = []; + private loopSourceData: Array = []; + private chartTotal: LitChartColumn | null | undefined; + private histogramSource: Array = []; + private rangeA: HistogramSourceConfig = new HistogramSourceConfig; + private rangeB: HistogramSourceConfig = new HistogramSourceConfig; + private rangeTotal: HistogramSourceConfig = new HistogramSourceConfig; + private clickThreadChildren: Array = []; + private isThreadStatesData: boolean = false; + private clickHighlightCondition: string = ''; + + + set data(threadStatesParam: SelectionParam) { + if (this.selectionParam === threadStatesParam) { return }; + this.schedSwitchTbl!.recycleDataSource = []; + this.queryButton!.style.pointerEvents = 'none'; + this.schedSwitchTbl!.loading = false; + this.isThreadStatesData = false; + // @ts-ignore + this.schedSwitchTbl!.value = []; + this.threadIdInput!.value = ''; + this.funcNameInput!.value = ''; + this.funcNameInput!.style.border = '1px solid rgb(151,151,151)'; + this.threadIdInput!.style.border = '1px solid rgb(151,151,151)'; + this.selectionParam = threadStatesParam; + this.canvansName!.textContent = 'sched switch平均分布图'; + this.isQueryButtonClick(false); + this.isSingleButtonFn(false); + this.isLoopButtonFn(false); + this.isCanvansDisplayFn(false); + } + initElements(): void { + this.schedSwitchTbl = this.shadowRoot!.querySelector('#tb-running'); + this.threadQueryDIV = this.shadowRoot?.querySelector('#data-cut'); + this.rightDIV = this.shadowRoot?.querySelector('#right'); + this.canvansName = this.shadowRoot!.querySelector('.sched-subheading'); + this.chartTotal = this.shadowRoot!.querySelector('#chart_total'); + this.threadIdInput = this.shadowRoot?.getElementById('cut-threadid') as HTMLInputElement; + this.funcNameInput = this.shadowRoot?.querySelector('#cut-thread-func') as HTMLInputElement; + this.singleBtn = this.shadowRoot?.querySelector('.single-btn'); + this.loopBtn = this.shadowRoot?.querySelector('.loop-btn'); + this.cycleALeftInput = this.shadowRoot?.getElementById('leftA') as HTMLInputElement; + this.cycleARightInput = this.shadowRoot?.getElementById('rightA') as HTMLInputElement; + this.cycleBLeftInput = this.shadowRoot?.getElementById('leftB') as HTMLInputElement; + this.cycleBRightInput = this.shadowRoot?.getElementById('rightB') as HTMLInputElement; + this.queryButton = this.shadowRoot?.querySelector('.query-btn'); + this.singleBtn?.addEventListener('click', (e) => { this.queryCutInfoFn(this.singleBtn!.innerHTML) }); + this.loopBtn?.addEventListener('click', (e) => { this.queryCutInfoFn(this.loopBtn!.innerHTML) }); + this.queryButton!.addEventListener('click', (e) => { this.queryCycleRangeData() }); + this.schedSwitchTbl!.addEventListener('row-click', (evt) => { this.clickTreeRowEvent(evt) }); + this.listenInputEvent() + } + listenInputEvent(): void { + this.cycleALeftInput!.addEventListener('input', (evt) => { + this.checkInputRangeFn( + this.cycleALeftInput, + this.cycleARightInput, + this.cycleBLeftInput, + this.cycleBRightInput, + this.cycleALeftInput!.value, + this.cycleARightInput!.value + ) + }) + this.cycleARightInput!.addEventListener('input', (evt) => { + this.checkInputRangeFn( + this.cycleARightInput, + this.cycleALeftInput, + this.cycleBLeftInput, + this.cycleBRightInput, + this.cycleALeftInput!.value, + this.cycleARightInput!.value + ) + }) + this.cycleBLeftInput!.addEventListener('input', (evt) => { + this.checkInputRangeFn( + this.cycleBLeftInput, + this.cycleBRightInput, + this.cycleALeftInput, + this.cycleARightInput, + this.cycleBLeftInput!.value, + this.cycleBRightInput!.value + ) + }) + this.cycleBRightInput!.addEventListener('input', (evt) => { + this.checkInputRangeFn( + this.cycleBRightInput, + this.cycleBLeftInput, + this.cycleALeftInput, + this.cycleARightInput, + this.cycleBLeftInput!.value, + this.cycleBRightInput!.value + ) + }) + } + clickTreeRowEvent(evt: Event): void { + //@ts-ignore + let data: TreeSwitchConfig = evt.detail.data as TreeSwitchConfig; + if (data.level === 'process') { + this.isCanvansDisplayFn(false); + this.threadFlag = ''; + } else if (data.level === 'thread') { + this.cycleALeftInput!.value = ''; + this.cycleARightInput!.value = ''; + this.cycleBLeftInput!.value = ''; + this.cycleBRightInput!.value = ''; + this.histogramSource = []; + this.clickThreadChildren = data.children; + this.queryButton!.style.pointerEvents = 'none'; + this.isCanvansDisplayFn(true); + this.isQueryButtonClick(false); + this.threadFlag = 'thread'; + this.clickHighlightCondition = `${data.process} - ${data.pid} - ${data.thread} - ${data.tid}`; + this.rangeTotal = { + count: data.count, + cycleNum: data.cycleNum, + average: data.cycleNum ? Math.ceil(data.count / data.cycleNum) : 0, + size: 'Total', + isHover: false, + color: '#2f72f8' + }; + this.histogramSource.push(this.rangeTotal); + data.isSelected = true; + this.schedSwitchTbl!.clearAllSelection(data); + this.schedSwitchTbl!.setCurrentSelection(data); + // SpSegmentationChart .setChartData('SCHED-SWITCH', data.children); + this.queryHistogramData() + } else if (data.level === 'cycle') { + if (this.threadFlag === 'thread') { + this.isCanvansDisplayFn(true); + } + if (this.clickHighlightCondition === `${data.process} - ${data.pid} - ${data.thread} - ${data.tid}`) { + data.isSelected = true; + this.schedSwitchTbl!.clearAllSelection(data); + this.schedSwitchTbl!.setCurrentSelection(data); + // SpSegmentationChart .tabHover('SCHED-SWITCH', true, data!.cycle); + } + } + } + + checkInputRangeFn( + firstInput: HTMLInputElement | null | undefined, + secondInput: HTMLInputElement | null | undefined, + thirdInput: HTMLInputElement | null | undefined, + fourInput: HTMLInputElement | null | undefined, + lVal: string, + rVal: string + ): void { + let leftVal: number = Number(lVal); + let rightVal: number = Number(rVal); + if (firstInput!.value !== '' && secondInput!.value !== '') { + if (firstInput!.value !== '' && secondInput!.value !== '') { + if (leftVal >= rightVal) { + firstInput!.style.color = 'red'; + this.queryButton!.style.pointerEvents = 'none'; + this.isQueryButtonClick(false); + } else if (leftVal < rightVal) { + firstInput!.style.color = 'black'; + secondInput!.style.color = 'black'; + this.queryButton!.style.pointerEvents = 'auto'; + this.isQueryButtonClick(true); + } + } + } else if ((firstInput!.value === '' && secondInput!.value !== '') || (firstInput!.value !== '' && secondInput!.value === '')) { + this.queryButton!.style.pointerEvents = 'none'; + this.isQueryButtonClick(false); + } else if (firstInput!.value === '' && secondInput!.value === '' && thirdInput!.value !== '' && fourInput!.value !== '') { + this.queryButton!.style.pointerEvents = 'auto'; + this.isQueryButtonClick(true); + } + if ((thirdInput!.value === '' && fourInput!.value !== '') || (thirdInput!.value !== '' && fourInput!.value === '')) { + this.queryButton!.style.pointerEvents = 'none'; + this.isQueryButtonClick(false); + } + } + + async initThreadStateData(threadParam: SelectionParam | null | undefined): Promise { + let leftStartNs: number = threadParam!.leftNs + threadParam!.recordStartNs; + let rightEndNs: number = threadParam!.rightNs + threadParam!.recordStartNs; + let res: Array = await querySchedThreadStates(threadParam!.threadIds, leftStartNs, rightEndNs); + if (res.length === 0) { + this.schedSwitchTbl!.recycleDataSource = []; + this.schedSwitchTbl!.loading = false; + this.clickTreeTitleFn(this.schedSwitchTbl!.recycleDataSource); + return; + } + this.singleSourceData = JSON.parse(JSON.stringify(res)); + this.loopSourceData = JSON.parse(JSON.stringify(res)); + this.isThreadStatesData = true; + } + + async queryCutInfoFn(btnHtml: string): Promise { + let threadId: string = this.threadIdInput!.value.trim(); + let threadFunName: string = this.funcNameInput!.value.trim(); + let leftStartNs: number = this.selectionParam!.leftNs + this.selectionParam!.recordStartNs; + let rightEndNs: number = this.selectionParam!.rightNs + this.selectionParam!.recordStartNs; + this.threadFlag = ''; + if (threadId !== "" && threadFunName !== "") { + this.threadIdInput!.style.border = '1px solid rgb(151,151,151)'; + this.funcNameInput!.style.border = '1px solid rgb(151,151,151)'; + //@ts-ignore + this.schedSwitchTbl!.value = []; + this.isCanvansDisplayFn(false); + this.schedSwitchTbl!.loading = true; + if (!this.isThreadStatesData) { this.initThreadStateData(this.selectionParam) }; + if (btnHtml === 'Single') { + await this.singleCutLogic(threadFunName, threadId, leftStartNs, rightEndNs) + }; + if (btnHtml === 'Loop') { + await this.loopCutLogic(threadFunName, threadId, leftStartNs, rightEndNs) + }; + } else { + if (threadId === "") { + this.threadIdInput!.style.border = '2px solid rgb(255,0,0)'; + this.threadIdInput!.setAttribute('placeholder', 'Please input thread id'); + } else { + this.threadIdInput!.style.border = '1px solid rgb(151,151,151)'; + }; + if (threadFunName === '') { + this.funcNameInput!.style.border = '2px solid rgb(255,0,0)'; + this.funcNameInput!.setAttribute('placeholder', 'Please input function name'); + } else { + this.funcNameInput!.style.border = '1px solid rgb(151,151,151)'; + } + } + } + + async singleCutLogic(threadFunName: string, threadId: string, leftStartNs: number, rightEndNs: number): Promise { + let cutData: Array = new Array(); + this.isSingleButtonFn(true); + this.isLoopButtonFn(false); + let res = await querySingleCutData(threadFunName, threadId, leftStartNs, rightEndNs); + if (res.length === 0) { + this.schedSwitchTbl!.recycleDataSource = []; + this.schedSwitchTbl!.loading = false; + this.clickTreeTitleFn(this.schedSwitchTbl!.recycleDataSource); + return; + }; + for (let idx = 0; idx < res.length; idx++) { + for (let i = 0; i < this.singleSourceData.length; i++) { + let singleItem = this.singleSourceData[i]; + if (!(singleItem.endTs < res[idx].cycleStartTime || singleItem.ts > res[idx].cycleEndTime)) { + let info = { + pid: singleItem.pid, + tid: singleItem.tid, + state: singleItem.state, + cycleStartTime: res[idx].cycleStartTime, + cycleEndTime: res[idx].cycleEndTime, + name: res[idx].name, + funId: res[idx].id, + runningCnt: singleItem.state === 'Running' ? 1 : 0, + }; + cutData.push(info); + } + } + } + this.handleSchedThreadData(cutData); + } + + async loopCutLogic(threadFunName: string, threadId: string, leftStartNs: number, rightEndNs: number): Promise { + let cutData: Array = new Array(); + this.isLoopButtonFn(true); + this.isSingleButtonFn(false); + this.schedSwitchTbl!.loading = true; + let res = await queryLoopCutData(threadFunName, threadId, leftStartNs, rightEndNs); + if (res.length === 0) { + this.schedSwitchTbl!.recycleDataSource = []; + this.schedSwitchTbl!.loading = false; + this.clickTreeTitleFn(this.schedSwitchTbl!.recycleDataSource); + return; + }; + for (let idx = 0; idx < res.length - 1; idx++) { + res[idx].cycleEndTime = res[idx + 1].cycleStartTime; + for (let i = 0; i < this.loopSourceData.length; i++) { + let loopItem = this.loopSourceData[i] + if (!(loopItem.endTs < res[idx].cycleStartTime || loopItem.ts > res[idx].cycleEndTime)) { + let info = { + pid: loopItem.pid, + tid: loopItem.tid, + state: loopItem.state, + cycleStartTime: res[idx].cycleStartTime, + cycleEndTime: res[idx + 1].cycleStartTime, + name: res[idx].name, + funId: res[idx].id, + runningCnt: loopItem.state === 'Running' ? 1 : 0, + } + cutData.push(info); + }; + }; + }; + this.handleSchedThreadData(cutData); + } + + handleSchedThreadData(result: Array): void { + let resultData: Array = new Array(); + if (result !== null && result.length > 0) { + for (let e of result) { + if (this.selectionParam!.processIds.includes(e.pid)) { + let process = Utils.PROCESS_MAP.get(e.pid); + let thread = Utils.THREAD_MAP.get(e.tid); + e.process = process === null || process!.length === 0 ? '[NULL]' : process!; + e.thread = thread === null || thread!.length === 0 ? '[NULL]' : thread!; + e.dur = e.cycleEndTime - e.cycleStartTime; + e.leftNS = e.cycleStartTime - this.selectionParam!.recordStartNs; + resultData.push(e); + } + } + this.translateIntoTreeData(resultData); + } + } + + translateIntoTreeData(data: Array): void { + let group = new Object(); + let groupArr: Array = new Array(); + if (data !== null && data.length > 0) { + data.forEach((slice) => { + let cycleItem: TreeSwitchConfig = { + title: `${slice.thread}`, + count: slice.runningCnt, + cycleNum: 1, + state: slice.state, + tid: slice.tid, + pid: slice.pid, + thread: slice.thread, + process: slice.process, + cycleStartTime: slice.leftNS, + duration: slice.dur, + level: 'cycle', + children: [] + }; + let threadItem: TreeSwitchConfig = { + title: `${slice.thread}` + `[${slice.tid}]`, + count: slice.runningCnt, + cycleNum: 1, + tid: slice.tid, + pid: slice.pid, + thread: slice.thread, + process: slice.process, + duration: slice.dur, + level: 'thread', + cycleStartTime: '', + children: [cycleItem] + }; + //@ts-ignore + if (group[`${slice.pid}`]) { + //@ts-ignore + let process = group[`${slice.pid}`]; + process.count += slice.runningCnt; + let thread = process.children.find((child: TreeSwitchConfig) => child.title === `${slice.thread}` + `[${slice.tid}]`); + if (thread) { + thread.count += slice.runningCnt; + let cycle = thread.children.find((child: TreeSwitchConfig) => child.cycleStartTime === slice.leftNS); + if (cycle) { + cycle.count += slice.runningCnt; + } else { + thread.cycleNum += 1; + process.cycleNum += 1; + thread.duration += slice.dur; + process.duration += slice.dur; + thread.children.push(cycleItem); + } + } else { + process.cycleNum += 1; + process.duration += slice.dur; + process.children.push(threadItem); + } + } else { + //@ts-ignore + group[`${slice.pid}`] = { + title: `${slice.process}` + `[${slice.pid}]`, + count: slice.runningCnt, + cycleNum: 1, + tid: slice.tid, + pid: slice.pid, + thread: slice.thread, + process: slice.process, + duration: slice.dur, + level: 'process', + cycleStartTime: '', + children: [threadItem], + }; + }; + }); + groupArr = Object.values(group); + for (let i = 0; i < groupArr.length; i++) { + this.addCycleNumber([groupArr[i]]); + } + this.schedSwitchTbl!.recycleDataSource = groupArr; + this.schedSwitchTbl!.loading = false; + this.clickTreeTitleFn(this.schedSwitchTbl!.recycleDataSource); + }; + } + + addCycleNumber(groupItem: Array): void { + let flagNumber: number = 0; + for (let idx = 0; idx < groupItem.length; idx++) { + //@ts-ignore + groupItem[idx].duration = (groupItem[idx].duration / 1000000.0).toFixed(3); + if (!(groupItem[idx].children.length)) { + flagNumber += 1; + groupItem[idx].cycle = flagNumber; + groupItem[idx].title = `cycle ${flagNumber}-` + groupItem[idx].title; + //@ts-ignore + groupItem[idx].cycleStartTime = (groupItem[idx].cycleStartTime / 1000000.0).toFixed(3); + } else { + this.addCycleNumber(groupItem[idx].children) + } + } + } + + clickTreeTitleFn(data: Array): void { + let labelList = this.schedSwitchTbl!.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); + if (labelList) { + for (let i = 0; i < labelList.length; i++) { + let lable = labelList[i].innerHTML; + labelList[i].addEventListener('click', (e) => { + if (lable.includes('Process') && i === 0) { + this.schedSwitchTbl!.setStatus(data, false); + this.schedSwitchTbl!.recycleDs = this.schedSwitchTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); + } else if (lable.includes('Thread') && i === 1) { + for (let item of data) { + item.status = true; + if (item.children !== undefined && item.children.length > 0) { + this.schedSwitchTbl!.setStatus(item.children, false); + } + } + this.schedSwitchTbl!.recycleDs = this.schedSwitchTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); + } else if (lable.includes('Cycle') && i === 2) { + this.schedSwitchTbl!.setStatus(data, true); + this.schedSwitchTbl!.recycleDs = this.schedSwitchTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand) + } + }) + + } + } + + } + + queryCycleRangeData(): void { + let cycleALeft: string = this.cycleALeftInput!.value.trim(); + let cycleARight: string = this.cycleARightInput!.value.trim(); + let cycleBLeft: string = this.cycleBLeftInput!.value.trim(); + let cycleBRight: string = this.cycleBRightInput!.value.trim(); + this.histogramSource = []; + this.histogramSource.push(this.rangeTotal); + if (cycleALeft !== '' && cycleARight !== '' && cycleALeft !== cycleARight) { + let countA: number = 0; + let rangeFilterA: Array = this.clickThreadChildren.filter((it: TreeSwitchConfig) => + Number(it.duration) >= Number(cycleALeft) && + Number(it.duration) < Number(cycleARight) + ); + rangeFilterA.forEach((item: TreeSwitchConfig) => { + countA += item.count + }); + this.rangeA = { + count: countA, + cycleNum: rangeFilterA.length, + average: rangeFilterA.length ? Math.ceil(countA / rangeFilterA.length) : 0, + size: 'Cycle A', + isHover: false, + color: '#ffab67' + }; + this.histogramSource.push(this.rangeA); + }; + if (cycleBLeft !== '' && cycleBRight !== '' && cycleBLeft !== cycleBRight) { + let countB: number = 0; + let rangeFilterB: Array = this.clickThreadChildren.filter((it: TreeSwitchConfig) => + Number(it.duration) >= Number(cycleBLeft) && + Number(it.duration) < Number(cycleBRight) + ); + rangeFilterB.forEach((item: TreeSwitchConfig) => { + countB += item.count + }); + this.rangeB = { + count: countB, + cycleNum: rangeFilterB.length, + average: rangeFilterB.length ? Math.ceil(countB / rangeFilterB.length) : 0, + size: 'Cycle B', + isHover: false, + color: '#a285d2' + }; + this.histogramSource.push(this.rangeB); + }; + this.queryHistogramData(); + } + + queryHistogramData(): void { + let source = []; + source = this.histogramSource.map((it: HistogramSourceConfig, index: number) => { + let data = { + cycle: it.size, + average: it.average, + visible: 1, + color: it.color, + }; + return data; + }); + this.chartTotal!.config = { + data: source, + appendPadding: 10, + xField: 'cycle', + yField: 'average', + notSort: true, + removeUnit: true, + seriesField: '', + color: (a) => { + if (a.cycle === 'Total') { + return '#2f72f8'; + } else if (a.cycle === 'Cycle A') { + return '#ffab67'; + } else if (a.cycle === 'Cycle B') { + return '#a285d2'; + } else { + return '#0a59f7'; + } + }, + tip: (a) => { + if (a && a[0]) { + let tip = ''; + for (let obj of a) { + tip = + `${tip} +
+
+
${obj.xLabel}:${obj.obj.average}
+
+ `; + }; + return tip; + } else { + return ''; + }; + }, + label: null, + }; + } + + isCanvansDisplayFn(flag: boolean): void { + if (!flag) { + this.setAttribute('isCanvansDisplay', '') + } else { + this.removeAttribute('isCanvansDisplay') + } + } + + isSingleButtonFn(flag: boolean): void { + if (flag) { + this.setAttribute('isSingleButton', '') + } else { + this.removeAttribute('isSingleButton') + } + } + + isLoopButtonFn(flag: boolean): void { + if (flag) { + this.setAttribute('isLoopButton', '') + } else { + this.removeAttribute('isLoopButton') + } + } + + isQueryButtonClick(flag: boolean): void { + if (flag) { + this.setAttribute('isQueryButton', '') + } else { + this.removeAttribute('isQueryButton') + } + } + + connectedCallback(): void { + super.connectedCallback(); + resizeObserver(this.parentElement!, this.schedSwitchTbl!); + } + initHtml(): string { + return ` + +
+ + +
+ + +
+
+
+
+ + + + + + + + + + +
+ + +
+ + ` + } +} diff --git a/ide/src/trace/database/SqlLite.ts b/ide/src/trace/database/SqlLite.ts index 28c4e6a71..5d8b81169 100644 --- a/ide/src/trace/database/SqlLite.ts +++ b/ide/src/trace/database/SqlLite.ts @@ -5887,3 +5887,87 @@ export const queryCpuKeyPathData = (threads: Array): Promise, leftStartNs: number, rightEndNs: number): Promise> => +query( + 'getTabThreadStates', + ` + select + B.id, + B.pid, + B.tid, + B.state, + B.type, + B.dur, + B.ts, + B.dur + B.ts as endTs + from + thread_state AS B + where + B.tid in (${tIds.join(',')}) + and + not ((B.ts + ifnull(B.dur,0) < $leftStartNs) or (B.ts > $rightEndNs)) + order by + B.pid; + `, + { $leftStartNs: leftStartNs, $rightEndNs: rightEndNs } +); + +export const querySingleCutData = (funcName: string, tIds: string, leftStartNs: number, rightEndNs: number): Promise> => +query( + 'querySingleCutData', + ` + select + c.id, + c.name, + c.ts as cycleStartTime, + c.ts + c.dur as cycleEndTime, + c.depth, + t.tid, + p.pid, + c.dur + 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 = '${funcName}' + and + t.tid = '${tIds}' + and + not ((c.ts < $leftStartNs) or (c.ts + ifnull(c.dur, 0) > $rightEndNs)) + `, + {$leftStartNs: leftStartNs, $rightEndNs: rightEndNs} +) + +export const queryLoopCutData = ( funcName: string, tIds: string, leftStartNs: number, rightEndNs: number): Promise> => +query ( + 'queryLoopCutData', + ` + select + c.id, + c.name, + c.ts as cycleStartTime, + c.depth, + t.tid, + p.pid + from callstack c + left join + thread t on c.callid = t.id + left join + process p on t.ipid = p.id + where + c.name = '${funcName}' + and + t.tid = '${tIds}' + and + not ((c.ts < $leftStartNs) or (c.ts > $rightEndNs)) + order by + c.ts + `, + { $leftStartNs: leftStartNs, $rightEndNs: rightEndNs } +) -- Gitee From e3ba4bab302486a99fd0c5477d7a629e7d3f2299 Mon Sep 17 00:00:00 2001 From: zhangyan Date: Thu, 14 Dec 2023 21:56:22 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangyan --- ide/src/trace/bean/SchedSwitchStruet.ts | 13 +-- .../sheet/schedswitch/TabPaneSchedSwitch.ts | 86 +++++++++---------- 2 files changed, 44 insertions(+), 55 deletions(-) diff --git a/ide/src/trace/bean/SchedSwitchStruet.ts b/ide/src/trace/bean/SchedSwitchStruet.ts index 6182c5128..40aee1358 100644 --- a/ide/src/trace/bean/SchedSwitchStruet.ts +++ b/ide/src/trace/bean/SchedSwitchStruet.ts @@ -13,17 +13,6 @@ * limitations under the License. */ -export class InitThreadConfig { - dur: number = 0; - endTs: number = 0; - id: number = -1; - pid: number = -1; - state: string = ''; - tid: number = -1; - ts: number = -1 - type: string = '' -} - export class TreeSwitchConfig { count: number = 0; cycleNum: number = 1; @@ -58,7 +47,7 @@ export class ThreadInitConfig { endTs: number = 0; id: number = 0; pid: number = -1; - state?: string = ''; + state: string = ''; tid: number = -1; ts: number = -1; type: string = '' diff --git a/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts b/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts index ab78aa9f5..202afa4f5 100644 --- a/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts +++ b/ide/src/trace/component/trace/sheet/schedswitch/TabPaneSchedSwitch.ts @@ -23,7 +23,6 @@ import { resizeObserver } from '../SheetUtils'; import { LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn'; import { type TreeSwitchConfig, - InitThreadConfig, HistogramSourceConfig, ThreadInitConfig, SchedThreadCutConfig @@ -48,8 +47,8 @@ export class TabPaneSchedSwitch extends BaseElement { private threadFlag: string = ''; private selectionParam: SelectionParam | undefined; private canvansName: HTMLDivElement | null | undefined; - private singleSourceData: Array = []; - private loopSourceData: Array = []; + private singleSourceData: Array = []; + private loopSourceData: Array = []; private chartTotal: LitChartColumn | null | undefined; private histogramSource: Array = []; private rangeA: HistogramSourceConfig = new HistogramSourceConfig; @@ -359,7 +358,7 @@ export class TabPaneSchedSwitch extends BaseElement { } translateIntoTreeData(data: Array): void { - let group = new Object(); + let group: { [key: number]: any } = {}; let groupArr: Array = new Array(); if (data !== null && data.length > 0) { data.forEach((slice) => { @@ -390,45 +389,7 @@ export class TabPaneSchedSwitch extends BaseElement { cycleStartTime: '', children: [cycleItem] }; - //@ts-ignore - if (group[`${slice.pid}`]) { - //@ts-ignore - let process = group[`${slice.pid}`]; - process.count += slice.runningCnt; - let thread = process.children.find((child: TreeSwitchConfig) => child.title === `${slice.thread}` + `[${slice.tid}]`); - if (thread) { - thread.count += slice.runningCnt; - let cycle = thread.children.find((child: TreeSwitchConfig) => child.cycleStartTime === slice.leftNS); - if (cycle) { - cycle.count += slice.runningCnt; - } else { - thread.cycleNum += 1; - process.cycleNum += 1; - thread.duration += slice.dur; - process.duration += slice.dur; - thread.children.push(cycleItem); - } - } else { - process.cycleNum += 1; - process.duration += slice.dur; - process.children.push(threadItem); - } - } else { - //@ts-ignore - group[`${slice.pid}`] = { - title: `${slice.process}` + `[${slice.pid}]`, - count: slice.runningCnt, - cycleNum: 1, - tid: slice.tid, - pid: slice.pid, - thread: slice.thread, - process: slice.process, - duration: slice.dur, - level: 'process', - cycleStartTime: '', - children: [threadItem], - }; - }; + this.addChildNodes(group, cycleItem, threadItem, slice) }); groupArr = Object.values(group); for (let i = 0; i < groupArr.length; i++) { @@ -439,7 +400,46 @@ export class TabPaneSchedSwitch extends BaseElement { this.clickTreeTitleFn(this.schedSwitchTbl!.recycleDataSource); }; } + addChildNodes(group: { [key: number]: TreeSwitchConfig }, cycleItem: TreeSwitchConfig, threadItem: TreeSwitchConfig, slice: SchedThreadCutConfig) { + if (group[`${slice.pid}`]) { + let process = group[`${slice.pid}`]; + process.count += slice.runningCnt; + let thread = process.children.find((child: TreeSwitchConfig) => child.title === `${slice.thread}` + `[${slice.tid}]`); + if (thread) { + thread.count += slice.runningCnt; + let cycle = thread.children.find((child: TreeSwitchConfig) => child.cycleStartTime === slice.leftNS); + if (cycle) { + cycle.count += slice.runningCnt; + } else { + + thread.cycleNum += 1; + process.cycleNum += 1; + (thread.duration as number) += (slice.dur as number); + (process.duration as number) += (slice.dur as number); + thread.children.push(cycleItem); + } + } else { + process.cycleNum += 1; + (process.duration as number) += (slice.dur as number); + process.children.push(threadItem); + } + } else { + group[`${slice.pid}`] = { + title: `${slice.process}` + `[${slice.pid}]`, + count: slice.runningCnt, + cycleNum: 1, + tid: slice.tid, + pid: slice.pid, + thread: slice.thread, + process: slice.process, + duration: slice.dur, + level: 'process', + cycleStartTime: '', + children: [threadItem], + }; + }; + } addCycleNumber(groupItem: Array): void { let flagNumber: number = 0; for (let idx = 0; idx < groupItem.length; idx++) { -- Gitee