From 1aa6f956860a037d761faa75d0f6bcb8b78997b2 Mon Sep 17 00:00:00 2001 From: zhangyan Date: Thu, 25 Jul 2024 11:26:49 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:=E5=BC=82=E6=AD=A5=E8=81=9A=E5=90=88?= =?UTF-8?q?=E4=B8=8B=E6=96=B0=E5=A2=9Ebusiness=20first=E5=92=8Cthread=20fi?= =?UTF-8?q?rst=E7=9A=84=E4=B8=8B=E6=9D=A5=E9=80=89=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangyan --- ide/src/trace/bean/BoxSelection.ts | 8 +- ide/src/trace/component/SpFlags.ts | 122 +++++++++++------- .../trace/component/chart/SpProcessChart.ts | 58 +++++---- .../trace/component/trace/base/TraceSheet.ts | 4 +- .../trace/sheet/cpu/TabPaneBoxChild.ts | 4 +- .../trace/sheet/process/TabPaneSliceChild.ts | 8 +- .../trace/sheet/process/TabPaneSlices.ts | 6 + ide/src/trace/database/sql/Func.sql.ts | 50 ++++++- 8 files changed, 170 insertions(+), 90 deletions(-) diff --git a/ide/src/trace/bean/BoxSelection.ts b/ide/src/trace/bean/BoxSelection.ts index 12858184..abea479d 100644 --- a/ide/src/trace/bean/BoxSelection.ts +++ b/ide/src/trace/bean/BoxSelection.ts @@ -1272,7 +1272,9 @@ export class SliceBoxJumpParam { processId: Array = []; threadId: Array = []; name: string[] | undefined | null; - isJumpPage: boolean | undefined + isJumpPage: boolean | undefined; + asyncNames: Array = []; + asyncCatNames: Array = []; } export class SelectionData { @@ -1306,7 +1308,9 @@ export class SelectionData { ts: number = 0; dur: number = 0; tabTitle: string = ''; - allName: string[] | undefined + allName: string[] | undefined; + asyncNames: Array = []; + asyncCatNames: Array = []; } export class Counter { diff --git a/ide/src/trace/component/SpFlags.ts b/ide/src/trace/component/SpFlags.ts index 2e031762..1e527a07 100644 --- a/ide/src/trace/component/SpFlags.ts +++ b/ide/src/trace/component/SpFlags.ts @@ -15,6 +15,21 @@ import { BaseElement, element } from '../../base-ui/BaseElement'; import { SpFlagHtml } from './SpFlag.html'; +const VSYNC_VAL = { + 'VsyncGeneratior': 'H:VsyncGenerator', + 'Vsync-rs': 'H:rs_SendVsync', + 'Vsync-app': 'H:app_SendVsync' +} + +const CAT_SORT = { + 'Business first': 'business', + 'Thread first': 'thread' +} + +const CONFIG_STATE = { + 'VSync': ['vsyncValue', 'VsyncGeneratior'], + 'Start&Finish Trace Category': ['catValue', 'Business first'] +} @element('sp-flags') export class SpFlags extends BaseElement { @@ -36,7 +51,7 @@ export class SpFlags extends BaseElement { configDiv.className = 'flag-widget'; return configDiv; } - + //控制按钮设置为'Disabled'时,我们需要给一个默认值 private createCustomDiv(config: FlagConfigItem, configDiv: HTMLDivElement): void { let configHadDiv = document.createElement('div'); configHadDiv.className = 'flag-head-div'; @@ -56,26 +71,7 @@ export class SpFlags extends BaseElement { configSelect.appendChild(configOption); }); configSelect.addEventListener('change', () => { - let title = configSelect.getAttribute('title'); - FlagsConfig.updateFlagsConfig(title!, configSelect.selectedOptions[0].value); - if (title === 'VSync' && configSelect.selectedOptions[0].value === 'Enabled') { - let vsyncSelect = this.shadowRoot?.querySelector('#vsyncSelect'); - vsyncSelect?.removeAttribute('disabled'); - } - if (title === 'VSync' && configSelect.selectedOptions[0].value === 'Disabled') { - let vsyncSelect = this.shadowRoot?.querySelector('#vsyncSelect'); - vsyncSelect?.childNodes.forEach((child: ChildNode) => { - let selectEl = child as HTMLOptionElement; - if (child.textContent === 'VsyncGenerator') { - selectEl.selected = true; - FlagsConfig.updateFlagsConfig('vsyncValue', selectEl.value); - } else { - selectEl.selected = false; - } - }); - - vsyncSelect?.setAttribute('disabled', 'disabled'); - } + this.flagSelectListener(configSelect); }); let description = document.createElement('div'); description.className = 'flag-des-div'; @@ -85,7 +81,30 @@ export class SpFlags extends BaseElement { configDiv.appendChild(configHadDiv); configDiv.appendChild(description); } + //监听flag-select的状态选择 + private flagSelectListener(configSelect: any): void { + let title = configSelect.getAttribute('title'); + let listSelect = this.shadowRoot?.querySelector(`#${CONFIG_STATE[title as keyof typeof CONFIG_STATE][0]}`); + FlagsConfig.updateFlagsConfig(title!, configSelect.selectedOptions[0].value); + if (CONFIG_STATE[title as keyof typeof CONFIG_STATE]) { + if (configSelect.selectedOptions[0].value === 'Enabled') { + listSelect?.removeAttribute('disabled'); + } else { + listSelect?.childNodes.forEach((child: ChildNode) => { + let selectEl = child as HTMLOptionElement; + if (child.textContent === CONFIG_STATE[title as keyof typeof CONFIG_STATE][1]) { + selectEl.selected = true; + FlagsConfig.updateFlagsConfig(CONFIG_STATE[title as keyof typeof CONFIG_STATE][0], selectEl.value); + } else { + selectEl.selected = false; + } + }); + listSelect?.setAttribute('disabled', 'disabled'); + } + } + } + //初始化Flag对应的内容 private initConfigList(): void { let allConfig = FlagsConfig.getAllFlagConfig(); allConfig.forEach((config) => { @@ -130,7 +149,14 @@ export class SpFlags extends BaseElement { } if (config.title === 'VSync') { - let configFooterDiv = this.createVsyncOption(); + let configKey = CONFIG_STATE['VSync' as keyof typeof CONFIG_STATE][0]; + let configFooterDiv = this.createPersonOption(VSYNC_VAL, configKey, config.addInfo!.vsyncValue, config.title); + configDiv.appendChild(configFooterDiv); + } + + if (config.title === 'Start&Finish Trace Category') { + let configKey = CONFIG_STATE['Start&Finish Trace Category' as keyof typeof CONFIG_STATE][0]; + let configFooterDiv = this.createPersonOption(CAT_SORT, configKey, config.addInfo!.catValue, config.title) configDiv.appendChild(configFooterDiv); } @@ -138,47 +164,38 @@ export class SpFlags extends BaseElement { }); } - private createVsyncOption(): HTMLDivElement { + private createPersonOption(list: any, key: string, defaultKey: string, parentOption: string): HTMLDivElement { let configFooterDiv = document.createElement('div'); configFooterDiv.className = 'config_footer'; let vsyncLableEl = document.createElement('lable'); - vsyncLableEl.className = 'vsync_lable'; + vsyncLableEl.className = 'list_lable'; let vsyncTypeEl = document.createElement('select'); - vsyncTypeEl.setAttribute('id', 'vsyncSelect'); + vsyncTypeEl.setAttribute('id', key); vsyncTypeEl.className = 'flag-select'; - let vsyncGenOption = document.createElement('option'); // VsyncGeneratior = H:VsyncGenerator - vsyncGenOption.value = 'H:VsyncGenerator'; - vsyncGenOption.textContent = 'VsyncGenerator'; - vsyncGenOption.selected = true; - vsyncTypeEl.appendChild(vsyncGenOption); - - let vsyncRsOption = document.createElement('option'); // Vsync-rs = H:rs_SendVsync - vsyncRsOption.value = 'H:rs_SendVsync'; - vsyncRsOption.textContent = 'Vsync-rs'; - vsyncTypeEl.appendChild(vsyncRsOption); - - let vsyncAppOption = document.createElement('option'); // Vsync-app = H:app_SendVsync - vsyncAppOption.value = 'H:app_SendVsync'; - vsyncAppOption.textContent = 'Vsync-app'; - vsyncTypeEl.appendChild(vsyncAppOption); - - FlagsConfig.updateFlagsConfig('vsyncValue', vsyncGenOption.value); + //根据给出的list遍历添加option下来选框 + for(let k of Object.keys(list)) { + let option = document.createElement('option'); // VsyncGeneratior = H:VsyncGenerator + option.value = list[k]; + option.textContent = k; + if (list[k] === defaultKey) { + option.selected = true; + FlagsConfig.updateFlagsConfig(key, option.value); + } + vsyncTypeEl.appendChild(option); + } vsyncTypeEl.addEventListener('change', function () { let selectValue = this.selectedOptions[0].value; - console.log(this); - console.log(this.selectedOptions[0]); - console.log(this.selectedOptions[0].value); - FlagsConfig.updateFlagsConfig('vsyncValue', selectValue); + FlagsConfig.updateFlagsConfig(key, selectValue); }); let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); let flagsItemJson = JSON.parse(flagsItem!); - let vsync = flagsItemJson.VSync; + let vsync = flagsItemJson[parentOption]; if (vsync === 'Enabled') { vsyncTypeEl.removeAttribute('disabled'); } else { vsyncTypeEl.setAttribute('disabled', 'disabled'); - FlagsConfig.updateFlagsConfig('vsyncValue', vsyncGenOption.value); + FlagsConfig.updateFlagsConfig(key, defaultKey); } configFooterDiv.appendChild(vsyncLableEl); configFooterDiv.appendChild(vsyncTypeEl); @@ -233,6 +250,7 @@ export class FlagsConfig { title: 'VSync', switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], describeContent: 'VSync Signal drawing', + addInfo: {vsyncValue: VSYNC_VAL['VsyncGeneratior'] }, }, { title: 'LTPO', @@ -243,6 +261,7 @@ export class FlagsConfig { title: 'Start&Finish Trace Category', switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], describeContent: 'Asynchronous trace aggregation', + addInfo: {catValue: CAT_SORT['Business first'] }, }, { title: 'UserPluginsRow', @@ -353,6 +372,13 @@ export class FlagsConfig { } return enable; } + //获取Cat的二级下拉选框所选的内容 + static getSecondarySelectValue(value: string): string { + let list = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); + let listJson = JSON.parse(list!); + let catSelectValue = listJson[value]; + return catSelectValue + } static updateFlagsConfig(key: string, value: unknown): void { let flagsConfigStr = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts index 50a6ce3e..8e7d623e 100644 --- a/ide/src/trace/component/chart/SpProcessChart.ts +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -1258,25 +1258,21 @@ export class SpProcessChart { //Async Function addAsyncFunction(it: { pid: number; processName: string | null }, processRow: TraceRow): void { let isCategoryAsyncfunc: boolean = FlagsConfig.getFlagsConfigEnableStatus('Start&Finish Trace Category'); + let asyncRemoveCatArr: any, asyncCat: any, setArrayLenThanOne: any, setArrayLenOnlyOne: any; //@ts-ignore let asyncFuncList = this.processAsyncFuncMap[it.pid] || []; if (!asyncFuncList.length) { return; } + let flag = FlagsConfig.getSecondarySelectValue('catValue') === 'business'; if (isCategoryAsyncfunc) {//聚合异步trace - let { asyncRemoveCatArr, asyncCatMap } = this.hanldCategoryAsyncFunc(asyncFuncList); - let { setArrayLenThanOne, setArrayLenOnlyOne } = this.hanldAsyncFunc(it, asyncRemoveCatArr); - //处理cat不为null和length等于1的数据 - let aggregateData = { ...Object.fromEntries(asyncCatMap), ...setArrayLenOnlyOne }; - Reflect.ownKeys(aggregateData).map((key: any) => { + ({ asyncRemoveCatArr, asyncCat } = this.hanldCatFunc(asyncFuncList, flag));//处理是否cat + ({ setArrayLenThanOne, setArrayLenOnlyOne } = this.hanldAsyncFunc(it, asyncRemoveCatArr));//len等于0和大于0的分类 + let aggregateData = { ...asyncCat, ...setArrayLenThanOne, ...setArrayLenOnlyOne }; + Reflect.ownKeys(aggregateData).map((key: any) => {//处理business first和length大于1的数据 let param: Array = aggregateData[key]; this.makeAddAsyncFunction(param, it, processRow, key); }) - //处理length大于1的数据,不传key值 - Reflect.ownKeys(setArrayLenThanOne).map((key: any) => { - let param: Array = setArrayLenThanOne[key]; - this.makeAddAsyncFunction(param, it, processRow); - }) } else { //不聚合异步trace let asyncFuncGroup = Utils.groupBy(asyncFuncList, 'funName'); @@ -1306,32 +1302,40 @@ export class SpProcessChart { this.toAsyncFuncCache(asyncFunctions[index], `${asyncFunctions[i].funName}-${it.pid}`);//处理缓存的异步trace数据缺失的字段 }); } - this.lanesConfig(asyncFunctions, it, processRow); + this.lanesConfig(asyncFunctions, it, processRow, `${asyncFunctions[0].funName}`); }); } } //处理CategoryAsyncFunc - hanldCategoryAsyncFunc( - asyncFuncList: Array - ): { asyncRemoveCatArr: Array, asyncCatMap: Map> } { + hanldCatFunc( + asyncFuncList: Array, + flag: boolean + ): { asyncRemoveCatArr: Array, asyncCat: any } { + let asyncCat; + let asyncCatArr = new Array(); let asyncCatMap: Map = new Map(); let asyncRemoveCatArr = new Array(); //取出cat字段(category)不为null的数据 for (let i = 0; i < asyncFuncList.length; i++) { const el = asyncFuncList[i]; if (el.cat !== null) { - if (asyncCatMap.has(`${el.cat}:${el.threadName} ${el.tid}`)) { - let item: Array = asyncCatMap.get(`${el.cat}:${el.threadName} ${el.tid}`); - item.push(el); - } else { - asyncCatMap.set(`${el.cat}:${el.threadName} ${el.tid}`, [el]); + if (flag) {//business first + asyncCatArr.push(el); + } else {//thread first + if (asyncCatMap.has(`${el.cat}:${el.threadName} ${el.tid}`)) { + let item: Array = asyncCatMap.get(`${el.cat}:${el.threadName} ${el.tid}`); + item.push(el); + } else { + asyncCatMap.set(`${el.cat}:${el.threadName} ${el.tid}`, [el]); + } } } else { //取cat字段为null的数据 asyncRemoveCatArr.push(el); } } - return { asyncRemoveCatArr, asyncCatMap }; + asyncCat = flag ? Utils.groupBy(asyncCatArr, 'cat') : Object.fromEntries(asyncCatMap) + return { asyncRemoveCatArr, asyncCat }; } //处理cat字段为null的数据,按funname分类,分别按len>1和=1去处理 hanldAsyncFunc( @@ -1348,7 +1352,7 @@ export class SpProcessChart { let asyncFunctions: Array = asyncFuncGroup[key]; if (asyncFunctions.length > 1) { //@ts-ignore - setArrayLenThanOne[`${asyncFunctions[0].funName}-${it.pid}`] = asyncFunctions; + setArrayLenThanOne[key] = asyncFunctions; } else if (asyncFunctions.length === 1) { funcArr.push(...asyncFunctions); } @@ -1368,7 +1372,7 @@ export class SpProcessChart { asyncFunctions: any[], it: { pid: number; processName: string | null }, processRow: TraceRow, - key?: string + key: string ) { let maxDepth: number = -1; let i = 0; @@ -1394,7 +1398,7 @@ export class SpProcessChart { mapDepth.set(`${maxDepth}`, { et: itemEndTime }); param.depth = maxDepth; } - this.toAsyncFuncCache(param, key ? key : `${asyncFunctions[i].funName}-${it.pid}`); + this.toAsyncFuncCache(param, `${key}-${it.pid}`); normalData.push(param); } else { noEndData.push(param); @@ -1411,7 +1415,7 @@ export class SpProcessChart { let index = i; maxDepth++; noEndData[index].depth = maxDepth; - this.toAsyncFuncCache(noEndData[index], key ? key : `${asyncFunctions[i].funName}-${it.pid}`); + this.toAsyncFuncCache(noEndData[index], `${key}-${it.pid}`); }); } this.lanesConfig([...normalData, ...noEndData], it, processRow, key); @@ -1422,13 +1426,13 @@ export class SpProcessChart { asyncFunctions: any[], it: { pid: number; processName: string | null }, processRow: TraceRow, - key?: string + key: string ) { const maxHeight = this.calMaxHeight(asyncFunctions); const namesSet = new Set(asyncFunctions.map((item) => item.funName)); const asyncFuncName = Array.from(namesSet); let funcRow = TraceRow.skeleton(); - funcRow.rowId = key ? key : `${asyncFunctions[0].funName}-${it.pid}`; + funcRow.rowId = `${key}-${it.pid}`; funcRow.asyncFuncName = asyncFuncName; funcRow.asyncFuncNamePID = it.pid; funcRow.rowType = TraceRow.ROW_TYPE_FUNC; @@ -1438,7 +1442,7 @@ export class SpProcessChart { funcRow.style.width = '100%'; funcRow.style.height = `${maxHeight}px`; funcRow.setAttribute('height', `${maxHeight}`); - funcRow.name = key ? key : `${asyncFunctions[0].funName}`; + funcRow.name = key; funcRow.setAttribute('children', ''); funcRow.findHoverStruct = (): void => { FuncStruct.hoverFuncStruct = funcRow.getHoverStruct(); diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index 5c330cef..6ba609df 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -1131,7 +1131,9 @@ export class TraceSheet extends BaseElement { param.rightNs = this.selection!.rightNs; param.processId = this.selection!.processIds; param.threadId = this.selection!.funTids;//@ts-ignore2 - param.name = e.detail.allName ? e.detail.allName : [e.detail.name]; + param.name = e.detail.allName ? e.detail.allName : [e.detail.name];//@ts-ignore2 + param.asyncNames = e.detail.asyncNames;//@ts-ignore2 + param.asyncCatNames = e.detail.asyncCatNames; param.isJumpPage = true; (pane.children.item(0) as TabPaneSliceChild).data = param; } diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts index 16b3fe71..f58dd140 100644 --- a/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts @@ -96,9 +96,9 @@ export class TabPaneBoxChild extends BaseElement { e.prior = prioObj ? prioObj.priority : '-'; e.core = e.cpu === undefined || e.cpu === null ? '-' : `CPU${e.cpu}`; let processInfo: string | undefined = Utils.getInstance().getProcessMap().get(e.pid); - e.processName = `${processInfo === undefined || processInfo === null ? 'process' : processInfo}(${e.pid})`; + e.processName = `${processInfo === undefined || processInfo === null ? 'process' : processInfo}[${e.pid}]`; let threadInfo: string | undefined = Utils.getInstance().getThreadMap().get(e.tid); - e.threadName = `${threadInfo === undefined || threadInfo === null ? 'thread' : threadInfo}(${e.tid})`; + e.threadName = `${threadInfo === undefined || threadInfo === null ? 'thread' : threadInfo}[${e.tid}]`; e.note = '-'; }); this.boxChildSource = result; diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneSliceChild.ts b/ide/src/trace/component/trace/sheet/process/TabPaneSliceChild.ts index a32d06ba..2c0f4f8c 100644 --- a/ide/src/trace/component/trace/sheet/process/TabPaneSliceChild.ts +++ b/ide/src/trace/component/trace/sheet/process/TabPaneSliceChild.ts @@ -18,7 +18,7 @@ import { LitTable } from '../../../../../base-ui/table/lit-table'; import { SelectionData, SliceBoxJumpParam } from '../../../../bean/BoxSelection'; import { Utils } from '../../base/Utils'; import { resizeObserver } from '../SheetUtils'; -import { getTabDetails } from '../../../../database/sql/Func.sql'; +import { getTabDetails, getCatDetails } from '../../../../database/sql/Func.sql'; @element('box-slice-child') export class TabPaneSliceChild extends BaseElement { @@ -68,7 +68,7 @@ export class TabPaneSliceChild extends BaseElement { //处理异步方法 getTabDetails(val.name!, val.processId, val.leftNs, val.rightNs, 'async').then((res1: any) => {//@ts-ignore //处理cat方法 - getTabDetails(val.name!, val.processId, val.leftNs, val.rightNs, 'cat').then((res2) => {//@ts-ignore + getCatDetails(val.name!, val.asyncCatNames!, val.processId, val.leftNs, val.rightNs).then((res2) => {//@ts-ignore //处理同步方法 getTabDetails(val.name!, val.processId, val.leftNs, val.rightNs, 'sync', val.threadId).then( (res3: any) => { @@ -81,8 +81,8 @@ export class TabPaneSliceChild extends BaseElement { e.absoluteTime = ((window as unknown).recordStartNS + e.startNs) / 1000000000; e.duration = e.duration / 1000000; e.state = Utils.getEndState(e.state)!; - e.processName = `${e.process === undefined || e.process === null ? 'process' : e.process}(${e.processId})`; - e.threadName = `${e.thread === undefined || e.thread === null ? 'thread' : e.thread}(${e.threadId})`; + e.processName = `${e.process === undefined || e.process === null ? 'process' : e.process}[${e.processId}]`; + e.threadName = `${e.thread === undefined || e.thread === null ? 'thread' : e.thread}[${e.threadId}]`; }); this.boxChildSource = result; if (this.sliceChildTbl) { diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts index cca69462..423975a1 100644 --- a/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts +++ b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts @@ -87,6 +87,10 @@ export class TabPaneSlices extends BaseElement { processSliceItem.wallDuration = parseFloat((processSliceItem.wallDuration / 1000000.0).toFixed(5)); //@ts-ignore processSliceItem.avgDuration = parseFloat((processSliceItem.avgDuration / 1000000.0).toFixed(5)); + //@ts-ignore + processSliceItem.asyncNames = asyncNames; + //@ts-ignore + processSliceItem.asyncCatNames = asyncCatNames; } let count = new SelectionData(); count.process = ' '; @@ -94,6 +98,8 @@ export class TabPaneSlices extends BaseElement { count.occurrences = sumOcc; count.tabTitle = 'Summary'; count.allName = processSlicesResult.map((item: any) => item.name); + count.asyncNames = asyncNames; + count.asyncCatNames = asyncCatNames; processSlicesResult.splice(0, 0, count); //@ts-ignore this.slicesSource = processSlicesResult; this.slicesTbl!.recycleDataSource = processSlicesResult; diff --git a/ide/src/trace/database/sql/Func.sql.ts b/ide/src/trace/database/sql/Func.sql.ts index 62e02799..de751595 100644 --- a/ide/src/trace/database/sql/Func.sql.ts +++ b/ide/src/trace/database/sql/Func.sql.ts @@ -354,11 +354,7 @@ export const getTabDetails = ( if (key === 'async') { asyncCondition = ` and c.cookie not null - ` - } else if (key === 'cat') { - catCondition = ` - and c.cookie not null - and c.cat not null + and c.parent_id not null ` } else if (key === 'sync') { syncCondition = ` @@ -394,7 +390,49 @@ export const getTabDetails = ( not ((C.ts - D.start_ts + C.dur < ${leftNS}) or (C.ts - D.start_ts > ${rightNS})) ${condition} ` return query('getTabDetails', sql, {}); - } + } + export const getCatDetails = ( + asyncNames: Array, + catName: Array, + asyncPid: Array, + leftNS: number, + rightNS: number + ): //@ts-ignore + Promise> => { + let sql = ` + SELECT + c.name AS name, + c.dur AS duration, + P.pid AS processId, + P.name AS process, + A.tid AS threadId, + A.name AS thread, + c.ts - D.start_ts as startNs + FROM + thread A,trace_range D + LEFT JOIN process P ON P.id = A.ipid + LEFT JOIN callstack C ON A.id = C.callid + where + C.ts > 0 + and + c.dur >= -1 + and + c.cookie not null + and + c.cat not null + and + c.parent_id is null + and + P.pid in (${asyncPid.join(',')}) + and + cat in (${catName.map((it) => "'" + it + "'").join(',')}) + and + c.name in (${asyncNames.map((it) => "'" + it + "'").join(',')}) + and + not ((C.ts - D.start_ts + C.dur < ${leftNS}) or (C.ts - D.start_ts > ${rightNS})) + ` + return query('getCatDetails', sql, {}); + } export const getTabSlicesAsyncCatFunc = ( asyncCatNames: Array, asyncCatPid: Array, -- Gitee From 7d7cec73dc356f4aec37d3af79d571fa74b86fbe Mon Sep 17 00:00:00 2001 From: liufei Date: Fri, 26 Jul 2024 17:33:36 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- ide/src/trace/component/chart/SpProcessChart.ts | 13 +++++++------ .../sheet/bpftrace/TabPaneSampleInstruction.ts | 8 ++++++++ .../bpftrace/TabPaneSampleInstructionSelection.ts | 8 ++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts index 7fb30374..9533fd1a 100644 --- a/ide/src/trace/component/chart/SpProcessChart.ts +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -306,7 +306,7 @@ export class SpProcessChart { funcRow.name = `${asyncFuncGroups[0].funName} ${key}`; funcRow.setAttribute('children', ''); //@ts-ignore - funcRow.supplierFrame = ():Promise=> { + funcRow.supplierFrame = (): Promise => { return processTouchEventDispatchDataSender(key, funcRow!).then((res: Array) => { this.touchEventDispatchSendCallback(res, funcRow, asyncFuncGroups); return res; @@ -331,7 +331,7 @@ export class SpProcessChart { return funcRow; } - // @ts-ignore + // @ts-ignore private touchEventDispatchSendCallback(res: Array, funcRow: TraceRow, asyncFuncGroups: Array): void { let isIntersect = (left: unknown, right: unknown): boolean => // @ts-ignore @@ -340,6 +340,7 @@ export class SpProcessChart { left.dur + right.dur; let depths: unknown = []; let createDepth = (currentDepth: number, index: number): void => { + // @ts-ignore if (depths[currentDepth] === undefined || !isIntersect(depths[currentDepth], res[index])) { //@ts-ignore res[index].depth = currentDepth; @@ -372,7 +373,7 @@ export class SpProcessChart { } } - // @ts-ignore + // @ts-ignore async init(isDistributed: boolean, parentRow?: TraceRow, traceId?: string): Promise { this.traceId = traceId; // @ts-ignore @@ -1271,7 +1272,7 @@ export class SpProcessChart { // @ts-ignore let modifiedObject = { ...object }; modifiedObject['startTime'] = modifiedObject['startTs']; - modifiedObject.remove('startTs'); + Reflect.deleteProperty(modifiedObject, "startTs"); modifiedObject.rowId = name; modifiedObject.type = 'func'; SpProcessChart.asyncFuncCache.push({ ...modifiedObject }); @@ -1288,7 +1289,7 @@ export class SpProcessChart { let { asyncRemoveCatArr, asyncCatMap } = this.hanldCategoryAsyncFunc(asyncFuncList); let { setArrayLenThanOne, setArrayLenOnlyOne } = this.hanldAsyncFunc(it, asyncRemoveCatArr); //处理cat不为null和length等于1的数据 - // @ts-ignore + // @ts-ignore let aggregateData = { ...Object.fromEntries(asyncCatMap), ...setArrayLenOnlyOne }; Reflect.ownKeys(aggregateData).map((key: unknown) => { let param: Array = aggregateData[key]; @@ -1296,7 +1297,7 @@ export class SpProcessChart { this.makeAddAsyncFunction(param, it, processRow, key); }); //处理length大于1的数据,不传key值 - // @ts-ignore + // @ts-ignore Reflect.ownKeys(setArrayLenThanOne).map((key: unknown) => { // @ts-ignore let param: Array = setArrayLenThanOne[key]; diff --git a/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstruction.ts b/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstruction.ts index 8e2128a1..fb45c2f5 100644 --- a/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstruction.ts +++ b/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstruction.ts @@ -416,13 +416,21 @@ export class TabPaneSampleInstruction extends BaseElement { subArr.some((obj: SampleStruct) => obj.begin === clickData.begin) ); //获取非unknown数据 + // @ts-ignore const knownRelation = relationData.filter((relation) => relation.name.indexOf('unknown') < 0); + // @ts-ignore propertyData.forEach((property: any) => { + // @ts-ignore const relation = knownRelation.find((relation) => relation.name === property.func_name); + // @ts-ignore relation.instructions = Math.ceil(property.instructions) || 1; + // @ts-ignore relation.hoverInstructions = Math.ceil(property.instructions); + // @ts-ignore relation.cycles = Math.ceil(property.cycles) || 1; + // @ts-ignore relation.hoverCycles = Math.ceil(property.cycles); + // @ts-ignore this.maxDepth = Math.max(this.maxDepth, relation.depth); }); //获取所有unknown数据 diff --git a/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstructionSelection.ts b/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstructionSelection.ts index b099c82a..a7f44310 100644 --- a/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstructionSelection.ts +++ b/ide/src/trace/component/trace/sheet/bpftrace/TabPaneSampleInstructionSelection.ts @@ -413,10 +413,12 @@ export class TabPaneSampleInstructionSelection extends BaseElement { getAvgInstructionData(instructionData: Array) { // @ts-ignore const length = instructionData[0].property.length; + // @ts-ignore const knowData = instructionData.filter((instruction) => instruction.name.indexOf('unknown') < 0); knowData.forEach((instruction) => { // @ts-ignore if (instruction.property.length > 0) { + // @ts-ignore const totalInstruction = instruction.property.reduce( (pre: number, cur: SampleStruct) => pre + Math.ceil(cur.instructions!), 0 @@ -426,13 +428,19 @@ export class TabPaneSampleInstructionSelection extends BaseElement { (pre: number, cur: SampleStruct) => pre + Math.ceil(cur.cycles!), 0 ); + // @ts-ignore instruction.instructions = Math.ceil(totalInstruction / length) || 1; + // @ts-ignore instruction.cycles = Math.ceil(totalCycles / length) || 1; + // @ts-ignore instruction.hoverInstructions = Math.ceil(totalInstruction / length); + // @ts-ignore instruction.hoverCycles = Math.ceil(totalCycles / length); + // @ts-ignore this.maxDepth = Math.max(this.maxDepth, instruction.depth); } }); + // @ts-ignore const unknownData = instructionData.filter((instruction) => instruction.name.indexOf('unknown') > -1); let instructionSum = 0; let cyclesSum = 0; -- Gitee From f99cbe00547949bd67500dacb850e416d97bd977 Mon Sep 17 00:00:00 2001 From: zhangyan Date: Sat, 27 Jul 2024 10:48:51 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat:=E4=BF=AE=E6=94=B9=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E5=8F=8A=E6=90=9C=E7=B4=A2=E4=B8=BA=E7=A9=BA=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangyan --- .../trace/component/chart/SpProcessChart.ts | 22 +++++++++++++------ .../trace/sheet/process/TabPaneSlices.ts | 4 ++++ ide/src/trace/database/sql/Func.sql.ts | 6 ++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts index 8c27928b..35cd86d6 100644 --- a/ide/src/trace/component/chart/SpProcessChart.ts +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -1280,7 +1280,7 @@ export class SpProcessChart { //Async Function addAsyncFunction(it: { pid: number; processName: string | null }, processRow: TraceRow): void { let isCategoryAsyncfunc: boolean = FlagsConfig.getFlagsConfigEnableStatus('Start&Finish Trace Category'); - let asyncRemoveCatArr: any, asyncCat: any, setArrayLenThanOne: any, setArrayLenOnlyOne: any; + let asyncRemoveCatArr: unknown[], asyncCat: unknown, setArrayLenThanOne: unknown, setArrayLenOnlyOne: unknown; //@ts-ignore let asyncFuncList = this.processAsyncFuncMap[it.pid] || []; if (!asyncFuncList.length) { @@ -1290,9 +1290,12 @@ export class SpProcessChart { if (isCategoryAsyncfunc) {//聚合异步trace ({ asyncRemoveCatArr, asyncCat } = this.hanldCatFunc(asyncFuncList, flag));//处理是否cat ({ setArrayLenThanOne, setArrayLenOnlyOne } = this.hanldAsyncFunc(it, asyncRemoveCatArr));//len等于0和大于0的分类 + //@ts-ignore let aggregateData = { ...asyncCat, ...setArrayLenThanOne, ...setArrayLenOnlyOne }; - Reflect.ownKeys(aggregateData).map((key: any) => {//处理business first和length大于1的数据 - let param: Array = aggregateData[key]; + Reflect.ownKeys(aggregateData).map((key: unknown) => {//处理business first和length大于1的数据 + //@ts-ignore + let param: Array = aggregateData[key]; + //@ts-ignore this.makeAddAsyncFunction(param, it, processRow, key); }) } else { @@ -1333,18 +1336,19 @@ export class SpProcessChart { this.toAsyncFuncCache(asyncFunctions[index], `${asyncFunctions[i].funName}-${it.pid}`);//处理缓存的异步trace数据缺失的字段 }); } + //@ts-ignore this.lanesConfig(asyncFunctions, it, processRow, `${asyncFunctions[0].funName}`); }); } } //处理CategoryAsyncFunc hanldCatFunc( - asyncFuncList: Array, + asyncFuncList: Array, flag: boolean - ): { asyncRemoveCatArr: Array, asyncCat: any } { + ): { asyncRemoveCatArr: Array, asyncCat: unknown } { let asyncCat; let asyncCatArr = new Array(); - let asyncCatMap: Map = new Map(); + let asyncCatMap: Map = new Map(); let asyncRemoveCatArr = new Array(); //取出cat字段(category)不为null的数据 for (let i = 0; i < asyncFuncList.length; i++) { @@ -1354,10 +1358,13 @@ export class SpProcessChart { if (flag) {//business first asyncCatArr.push(el); } else {//thread first + //@ts-ignore if (asyncCatMap.has(`${el.cat}:${el.threadName} ${el.tid}`)) { - let item: Array = asyncCatMap.get(`${el.cat}:${el.threadName} ${el.tid}`); + //@ts-ignore + let item: Array = asyncCatMap.get(`${el.cat}:${el.threadName} ${el.tid}`); item.push(el); } else { + //@ts-ignore asyncCatMap.set(`${el.cat}:${el.threadName} ${el.tid}`, [el]); } } @@ -1457,6 +1464,7 @@ export class SpProcessChart { maxDepth++; // @ts-ignore noEndData[index].depth = maxDepth; + //@ts-ignore this.toAsyncFuncCache(noEndData[index], `${key}-${it.pid}`); }); } diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts index 423975a1..8ec4a667 100644 --- a/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts +++ b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts @@ -344,6 +344,7 @@ export class TabPaneSlices extends BaseElement { let searchData: Array = []; let sumWallDuration: number = 0; let sumOccurrences: number = 0; + let nameSet: Array = []; if (str === '') { this.slicesTbl!.recycleDataSource = this.slicesSource; this.sliceSearchCount!.textContent = this.slicesSource.length - 1 + ''; @@ -351,6 +352,7 @@ export class TabPaneSlices extends BaseElement { this.slicesSource.forEach((item) => { if (item.name.toLowerCase().indexOf(str.toLowerCase()) !== -1) { searchData.push(item); + nameSet.push(item.name); sumWallDuration += item.wallDuration; sumOccurrences += item.occurrences; } @@ -358,6 +360,8 @@ export class TabPaneSlices extends BaseElement { let count: SelectionData = new SelectionData(); count.process = ''; count.name = ''; + count.allName = nameSet; + count.tabTitle = 'Summary'; count.wallDuration = Number(sumWallDuration.toFixed(3)); count.occurrences = sumOccurrences; searchData.unshift(count); diff --git a/ide/src/trace/database/sql/Func.sql.ts b/ide/src/trace/database/sql/Func.sql.ts index edfb64d5..0e34bb3e 100644 --- a/ide/src/trace/database/sql/Func.sql.ts +++ b/ide/src/trace/database/sql/Func.sql.ts @@ -367,7 +367,7 @@ export const getTabDetails = ( ${catCondition} ${syncCondition} ${`and P.pid in (${asyncPid.join(',')})`} - ${`and c.name in (${asyncNames.map((it) => "'" + it + "'").join(',')})`} + ${`and c.name in (${asyncNames.map((it) => "\"" + it + "\"").join(',')})`} ` let sql = ` SELECT @@ -425,9 +425,9 @@ export const getTabDetails = ( and P.pid in (${asyncPid.join(',')}) and - cat in (${catName.map((it) => "'" + it + "'").join(',')}) + c.cat in (${catName.map((it) => "\"" + it + "\"").join(',')}) and - c.name in (${asyncNames.map((it) => "'" + it + "'").join(',')}) + c.name in (${asyncNames.map((it) => "\"" + it + "\"").join(',')}) and not ((C.ts - D.start_ts + C.dur < ${leftNS}) or (C.ts - D.start_ts > ${rightNS})) ` -- Gitee From 5a8fa36f61ba64b9f09e436815f5f40744a787bb Mon Sep 17 00:00:00 2001 From: liufei Date: Sat, 27 Jul 2024 15:34:45 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=91=8A=E8=AD=A63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- ide/src/base-ui/select/LitSelect.ts | 17 ++-- ide/src/base-ui/table/lit-table.ts | 12 ++- ide/src/base-ui/tree/LitTree.ts | 6 +- ide/src/doc/quickstart_trace_streamer.html | 2 +- ide/src/trace/bean/BoxSelection.ts | 7 +- ide/src/trace/component/SpHelp.ts | 2 +- .../trace/component/SpSystemTrace.event.ts | 2 +- ide/src/trace/component/SpThirdParty.ts | 2 +- ide/src/trace/component/chart/FrameChart.ts | 14 ++- .../component/chart/SpGpuCounterChart.ts | 7 +- ide/src/trace/component/chart/SpLTPO.ts | 6 +- .../trace/component/chart/SpProcessChart.ts | 2 +- .../trace/component/setting/SpWebHdcShell.ts | 7 +- .../trace/component/trace/base/TraceSheet.ts | 94 ++++++++++++------- ide/src/trace/component/trace/base/Utils.ts | 4 +- .../TabPanePurgTotalComparisonAbility.ts | 3 +- 16 files changed, 113 insertions(+), 74 deletions(-) diff --git a/ide/src/base-ui/select/LitSelect.ts b/ide/src/base-ui/select/LitSelect.ts index 05b7aa02..d693e413 100644 --- a/ide/src/base-ui/select/LitSelect.ts +++ b/ide/src/base-ui/select/LitSelect.ts @@ -176,7 +176,7 @@ export class LitSelect extends BaseElement { selectDataSource.forEach(item => { if (valuesSet.has(item.value)) { flag = false; // 如果value有重复,就设置flag为false - return; + return; } valuesSet.add(item.value); }); @@ -195,7 +195,7 @@ export class LitSelect extends BaseElement { value: dateSourceBean.name ? dateSourceBean.name : dateSourceBean, // @ts-ignore name: dateSourceBean.name ? dateSourceBean.name : dateSourceBean, }; - } + } selectOption.textContent = optionData.name; selectOption.setAttribute('value', optionData.value); if (this.currentSelectedValue === optionData.value) { @@ -238,8 +238,7 @@ export class LitSelect extends BaseElement { ${selectHtmlStr(this.listHeight)}
- +
@@ -269,7 +268,7 @@ export class LitSelect extends BaseElement { icon.name = 'close'; let span = document.createElement('span'); // @ts-ignore tag.classList.add('tag'); // @ts-ignore - span.dataset['value'] = value; // @ts-ignore + span.dataset.value = value; // @ts-ignore span.textContent = text; // @ts-ignore tag.append(span); // @ts-ignore tag.append(icon); // @ts-ignore @@ -285,9 +284,9 @@ export class LitSelect extends BaseElement { ev.stopPropagation(); }; // @ts-ignore tag.value = value; // @ts-ignore - tag.dataset['value'] = value; // @ts-ignore + tag.dataset.value = value; // @ts-ignore tag.text = text; // @ts-ignore - tag.dataset['text'] = text; // @ts-ignore + tag.dataset.text = text; // @ts-ignore return tag; } @@ -621,9 +620,9 @@ export class LitSelect extends BaseElement { }); } - disconnectedCallback(): void {} + disconnectedCallback(): void { } - adoptedCallback(): void {} + adoptedCallback(): void { } attributeChangedCallback(name: unknown, oldValue: unknown, newValue: unknown): void { if (name === 'value' && this.selectInputEl) { diff --git a/ide/src/base-ui/table/lit-table.ts b/ide/src/base-ui/table/lit-table.ts index f1bc7e89..285db091 100644 --- a/ide/src/base-ui/table/lit-table.ts +++ b/ide/src/base-ui/table/lit-table.ts @@ -352,7 +352,7 @@ export class LitTable extends HTMLElement { this.theadElement!.append(rowElement); }); }); - this.shadowRoot!.addEventListener('load', function (event) {}); + this.shadowRoot!.addEventListener('load', function (event) { }); this.tableElement!.addEventListener('mouseout', (ev) => this.mouseOut()); this.treeElement && (this.treeElement!.style.transform = 'translateY(0px)'); this.tbodyElement && (this.tbodyElement!.style.transform = 'translateY(0px)'); @@ -631,7 +631,7 @@ export class LitTable extends HTMLElement { }); } - adoptedCallback(): void {} + adoptedCallback(): void { } getCheckRows(): unknown[] { // @ts-ignore @@ -639,7 +639,7 @@ export class LitTable extends HTMLElement { .map((a) => (a as unknown).data) .map((a) => { if ('children' in a) { - delete a['children']; + Reflect.deleteProperty(a, "chlidren") } return a; }); @@ -1525,14 +1525,15 @@ export class LitTable extends HTMLElement { } //自定义td点击事件 - dispatchTdClickEvent(td: unknown, column: any, rowData: unknown): void { + dispatchTdClickEvent(td: unknown, column: unknown, rowData: unknown): void { + // @ts-ignore if (column.hasAttribute('tdJump')) { //@ts-ignore td.style.color = '#208aed'; //@ts-ignore td.style.textDecoration = 'underline'; //@ts-ignore - td.onclick = (event: any) => { + td.onclick = (event: unknown): void => { this.dispatchEvent( new CustomEvent('td-click', { detail: {//@ts-ignore @@ -1541,6 +1542,7 @@ export class LitTable extends HTMLElement { composed: true, }) ); + // @ts-ignore event.stopPropagation(); }; } diff --git a/ide/src/base-ui/tree/LitTree.ts b/ide/src/base-ui/tree/LitTree.ts index a23c3c21..756848b4 100644 --- a/ide/src/base-ui/tree/LitTree.ts +++ b/ide/src/base-ui/tree/LitTree.ts @@ -334,7 +334,7 @@ export class LitTree extends BaseElement { this.contextMenu!.style.display = 'none'; } - onDrag(e: MouseEvent): void {} + onDrag(e: MouseEvent): void { } onDragStart(ev: MouseEvent): undefined { this.srcDragElement = ev.target; @@ -356,7 +356,7 @@ export class LitTree extends BaseElement { onDragOver(ev: MouseEvent): undefined { let node = ev.target as LitTreeNode; //@ts-ignore if (this.srcDragElement.data.key === node.data!.key) { - return; + return undefined; } //@ts-ignore let rect = (ev.currentTarget! as unknown).getBoundingClientRect(); if (ev.clientX >= rect.left + rect.width / 3 && ev.clientX < rect.left + rect.width) { @@ -389,7 +389,7 @@ export class LitTree extends BaseElement { let srcData = this.srcDragElement.data; //获取原节点的data数据 let dstData = (ev.target as LitTreeNode).data; //获取目标节点的data数据 if (srcData.key === dstData!.key) { - return; + return undefined; } //同一个节点不用处理 //@ts-ignore let srcElement = this.srcDragElement.parentElement; diff --git a/ide/src/doc/quickstart_trace_streamer.html b/ide/src/doc/quickstart_trace_streamer.html index 5676d805..3ca9d30e 100644 --- a/ide/src/doc/quickstart_trace_streamer.html +++ b/ide/src/doc/quickstart_trace_streamer.html @@ -892,7 +892,7 @@ TraceStreamer在解析数据过程中,使用ipid(internal pid)唯一标识进 lightBackGround[i].style.backgroundColor = '#32373F'; } } - }) + }); \ No newline at end of file diff --git a/ide/src/trace/bean/BoxSelection.ts b/ide/src/trace/bean/BoxSelection.ts index df88bba1..8e8c8b1a 100644 --- a/ide/src/trace/bean/BoxSelection.ts +++ b/ide/src/trace/bean/BoxSelection.ts @@ -1129,7 +1129,8 @@ export class SelectionParam { } //匹配id - pushDmaFence(it: TraceRow, sp: SpSystemTrace): void { + // @ts-ignore + pushDmaFence(it: TraceRow, sp: SpSystemTrace): void { if (it.rowType === TraceRow.ROW_TYPE_DMA_FENCE) { this.dmaFenceNameData.push(it.rowId!); } @@ -1273,7 +1274,7 @@ export class SliceBoxJumpParam { processId: Array = []; threadId: Array = []; name: string[] | undefined | null; - isJumpPage: boolean | undefined + isJumpPage: boolean | undefined; } export class SelectionData { @@ -1307,7 +1308,7 @@ export class SelectionData { ts: number = 0; dur: number = 0; tabTitle: string = ''; - allName: string[] | undefined + allName: string[] | undefined; } export class Counter { diff --git a/ide/src/trace/component/SpHelp.ts b/ide/src/trace/component/SpHelp.ts index e3ea7723..c9d040f1 100644 --- a/ide/src/trace/component/SpHelp.ts +++ b/ide/src/trace/component/SpHelp.ts @@ -278,7 +278,7 @@ export class SpHelp extends BaseElement { text: header.textContent!.trim() })); this.navbarContainer!.innerHTML = `