From 16bfad73b031621a06b15dfadf6d82ad90b61d82 Mon Sep 17 00:00:00 2001 From: liufei Date: Wed, 4 Dec 2024 15:11:59 +0800 Subject: [PATCH 01/13] =?UTF-8?q?hiperf=E8=8E=B7=E5=8F=96perfAnalysis?= =?UTF-8?q?=E9=A1=B5=E8=8E=B7=E5=8F=96=E6=9C=80=E5=BA=95=E5=B1=82=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E6=A0=88vaddr=5Fin=5Ffile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei (cherry picked from commit 6b71f8804994932147b9bd43974e15c27269439e) --- .../logic-worker/ProcedureLogicWorkerPerf.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 443502139..7ff0957a6 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -461,6 +461,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { `select c.name, c.callchain_id as sampleId, c.vaddr_in_file as vaddrInFile, + c.offset_to_vaddr as offsetToVaddr, c.file_id as fileId, c.depth, c.symbol_id as symbolId, @@ -1237,6 +1238,9 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { ) { let analysisSample = new PerfAnalysisSample( threadName, + lastCallChain.depth, + lastCallChain.vaddrInFile, + lastCallChain.offsetToVaddr, processName, lastCallChain.fileId, lastCallChain.fileName, @@ -1426,6 +1430,7 @@ export class PerfCallChain { sampleId: number = 0; callChainId: number = 0; vaddrInFile: number = 0; + offsetToVaddr:number = 0; tid: number = 0; pid: number = 0; name: number | string = 0; @@ -1499,6 +1504,7 @@ export class PerfCallChainMerageData extends ChartStruct { initChildren: PerfCallChainMerageData[] = []; type: number = 0; vaddrInFile: number = 0; + offsetToVaddr:number = 0; isSelected: boolean = false; searchShow: boolean = true; isSearch: boolean = false; @@ -1551,6 +1557,7 @@ export class PerfCallChainMerageData extends ChartStruct { currentNode.tid = sample.tid; currentNode.libName = callChain.fileName; currentNode.vaddrInFile = callChain.vaddrInFile; + currentNode.offsetToVaddr = callChain.offsetToVaddr; currentNode.lib = callChain.fileName; currentNode.addr = `${'0x'}${callChain.vaddrInFile.toString(16)}`; currentNode.canCharge = callChain.canCharge; @@ -1605,6 +1612,9 @@ export class PerfCmdLine { class PerfAnalysisSample extends PerfCountSample { threadName: string; + depth:number; + vaddr_in_file:number; + offset_to_vaddr:number; processName: string; libId: number; libName: string; @@ -1613,6 +1623,9 @@ class PerfAnalysisSample extends PerfCountSample { constructor( threadName: string, + depth:number, + vaddr_in_file:number, + offset_to_vaddr:number, processName: string, libId: number, libName: string, @@ -1621,6 +1634,9 @@ class PerfAnalysisSample extends PerfCountSample { ) { super(); this.threadName = threadName; + this.depth = depth; + this.vaddr_in_file = vaddr_in_file; + this.offset_to_vaddr = offset_to_vaddr; this.processName = processName; this.libId = libId; this.libName = libName; -- Gitee From 5c66e6b6a943804de0d77bd1bb5e5ea273352706 Mon Sep 17 00:00:00 2001 From: z30061262 Date: Thu, 5 Dec 2024 09:31:09 +0800 Subject: [PATCH 02/13] =?UTF-8?q?so=E3=80=81an=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=97=B6=E5=8F=91=E9=80=81=E5=88=B0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhuheng --- ide/src/trace/database/SqlLiteWorker.ts | 102 +++++++++++++++++++++++- ide/src/trace/database/TraceWorker.ts | 30 +++++++ ide/src/webSocket/Constants.ts | 5 ++ ide/src/webSocket/WebSocketManager.ts | 21 ++++- 4 files changed, 153 insertions(+), 5 deletions(-) diff --git a/ide/src/trace/database/SqlLiteWorker.ts b/ide/src/trace/database/SqlLiteWorker.ts index 29506f47a..3560a0e22 100644 --- a/ide/src/trace/database/SqlLiteWorker.ts +++ b/ide/src/trace/database/SqlLiteWorker.ts @@ -13,14 +13,21 @@ * limitations under the License. */ +import {WebSocketManager} from "../../webSocket/WebSocketManager"; + importScripts('sql-wasm.js'); // @ts-ignore import { temp_init_sql_list } from './TempSql'; import { execProtoForWorker } from './data-trafic/utils/ExecProtoForWorker'; import { TraficEnum } from './data-trafic/utils/QueryEnum'; +import {Constants, TypeConstants} from "../../webSocket/Constants"; let conn: unknown = null; - +let enc = new TextEncoder(); +let dec = new TextDecoder(); +const REQ_BUF_SIZE = 4 * 1024 * 1024; +let uploadSoActionId: string = ''; +const failedArray: Array = []; self.onerror = function (error): void { }; self.onmessage = async (e: unknown): Promise => { @@ -97,5 +104,98 @@ self.onmessage = async (e: unknown): Promise => { return []; } }); + } else if (action === 'upload-so') { + onmessageByUploadSoAction(e); + } +}; + +function onmessageByUploadSoAction(e: unknown): void { + // @ts-ignore + uploadSoActionId = e.data.id; + // @ts-ignore + const fileList = e.data.params as Array; + const file = fileList[0]; + const result = 'ok'; + if (fileList) { + fileList.sort((a, b) => b.size - a.size); + uploadAllFilesRecursively(fileList); + } + self.postMessage({ + id: uploadSoActionId, + action: 'upload-so', + results: { result: result, failedArray: failedArray }, + }); +} + +// 递归上传文件 +function uploadAllFilesRecursively(fileList: Array): void { + if (fileList.length === 0) { + console.log("All files have been uploaded."); + return; // 所有文件上传完成 + } + + // 上传第一个文件 + const file = fileList[0]; + uploadSoFile(file).then(() => { + console.log(`File ${file.name} uploaded successfully.`); + // 删除数组中的第一个元素 + fileList.shift(); + // 递归调用上传下一个文件 + uploadAllFilesRecursively(fileList); + }).catch((error) => { + console.error(`Failed to upload file: ${file.name}`, error); + // 继续上传下一个,即使失败也继续 + fileList.shift(); + uploadAllFilesRecursively(fileList); + }); +} + + +const uploadSoFile = async (file: File | null): Promise => { + if (file) { + let fileNameBuffer: Uint8Array | null = enc.encode(file.webkitRelativePath); + let fileNameLength = fileNameBuffer.length; + let writeSize = 0; + let wsInstance = WebSocketManager.getInstance() + const fileName = file.name; + let bufferIndex = 0; + while (writeSize < file.size) { + let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE); + let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); + let buffer: ArrayBuffer | null = await blob.arrayBuffer(); + let data: Uint8Array | null = new Uint8Array(buffer); + let fileTotalSize = file.size; + writeSize += sliceLen; + //@ts-ignore + if (wsInstance) { + // 构造包含元数据和文件内容的对象 + const dataObject = { + file_name: fileName, + buffer_index: bufferIndex, + buffer_size: sliceLen, + total_size: fileTotalSize, + is_last: writeSize >= file.size, + buffer: Array.from(data), // 将 Uint8Array 转换为普通数组,以便可以序列化为 JSON + }; + + // 将对象序列化为 JSON 字符串 + const dataString = JSON.stringify(dataObject); + + // 使用 TextEncoder 将字符串编码为 Uint8Array + const textEncoder = new TextEncoder(); + const encodedData = textEncoder.encode(dataString); + + // 通过 WebSocket 发送数据 + wsInstance.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); + } + + // 更新当前片段索引 + bufferIndex++; + data = null; + buffer = null; + blob = null; + } + file = null; + fileNameBuffer = null; } }; diff --git a/ide/src/trace/database/TraceWorker.ts b/ide/src/trace/database/TraceWorker.ts index 1923ed8af..18f3937e0 100644 --- a/ide/src/trace/database/TraceWorker.ts +++ b/ide/src/trace/database/TraceWorker.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import {WebSocketManager} from "../../webSocket/WebSocketManager"; + importScripts('trace_streamer_builtin.js'); import { execProtoForWorker } from './data-trafic/utils/ExecProtoForWorker'; import { QueryEnum, TraficEnum } from './data-trafic/utils/QueryEnum'; @@ -20,6 +22,7 @@ import { QueryEnum, TraficEnum } from './data-trafic/utils/QueryEnum'; import { temp_init_sql_list } from './TempSql'; // @ts-ignore import { BatchSphData } from '../proto/SphBaseData'; +import {Constants, TypeConstants} from "../../webSocket/Constants"; enum TsLogLevel { DEBUG = 0, @@ -1328,6 +1331,9 @@ const uploadSoFile = async (file: File | null): Promise => { wasmModule.HEAPU8.set(fileNameBuffer, addr); let writeSize = 0; let upRes = -1; + let wsInstance = WebSocketManager.getInstance() + const fileName = file.name; + let bufferIndex = 0; while (writeSize < file.size) { let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE); let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); @@ -1339,6 +1345,30 @@ const uploadSoFile = async (file: File | null): Promise => { writeSize += sliceLen; //@ts-ignore upRes = wasmModule._TraceStreamerDownloadELFEx(size, fileNameLength, sliceLen, 1); + if (wsInstance) { + // 构造包含元数据和文件内容的对象 + const dataObject = { + file_name: fileName, + buffer_index: bufferIndex, + buffer_size: sliceLen, + total_size: size, + is_last: writeSize >= file.size, + buffer: Array.from(data), // 将 Uint8Array 转换为普通数组,以便可以序列化为 JSON + }; + + // 将对象序列化为 JSON 字符串 + const dataString = JSON.stringify(dataObject); + + // 使用 TextEncoder 将字符串编码为 Uint8Array + const textEncoder = new TextEncoder(); + const encodedData = textEncoder.encode(dataString); + + // 通过 WebSocket 发送数据 + wsInstance.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); + } + + // 更新当前片段索引 + bufferIndex++; data = null; buffer = null; blob = null; diff --git a/ide/src/webSocket/Constants.ts b/ide/src/webSocket/Constants.ts index 91fb9c546..b1b752750 100644 --- a/ide/src/webSocket/Constants.ts +++ b/ide/src/webSocket/Constants.ts @@ -23,6 +23,10 @@ export class Constants { static GET_VERSION_CMD = 1; static UPDATE_SUCCESS_CMD = 2; // 升级成功 static UPDATE_FAIL_CMD = 4; // 升级失败 + static DISASSEMBLY_SAVE_CMD = 1; + static DISASSEMBLY_SAVE_BACK_CMD = 2; + static DISASSEMBLY_QUERY_CMD = 3; + static DISASSEMBLY_QUERY_BACK_CMD = 4; } export class TypeConstants { @@ -41,4 +45,5 @@ export class TypeConstants { static USB_GET_EVENT = 4; static USB_GET_APP = 5; static USB_GET_VERSION = 6; + static DISASSEMBLY_TYPE = 10; } \ No newline at end of file diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index 27861b923..76620233b 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -56,7 +56,7 @@ export class WebSocketManager { this.websocket.binaryType = 'arraybuffer'; this.websocket.onopen = (): void => { this.status = GetStatuses.CONNECTED; - // 设置心跳定时器 + // 设置心跳定时器 this.sendHeartbeat(); // 连接后登录 this.login(); @@ -83,6 +83,7 @@ export class WebSocketManager { this.initLoginInfo(); this.clearHeartbeat(); }; + WebSocketManager.getInstance()!.registerMessageListener(TypeConstants.DISASSEMBLY_TYPE, this.webSocketCallBack, () => {}); } /** @@ -99,7 +100,7 @@ export class WebSocketManager { this.businessMessage(decode); } } - + // 登录 loginMessage(decode: MessageParam): void { if (decode.cmd === Constants.LOGIN_CMD) { @@ -133,7 +134,7 @@ export class WebSocketManager { this.finalStatus(); } else if (decode.cmd === Constants.UPDATE_FAIL_CMD) { // 升级失败 this.status = GetStatuses.UPGRADEFAILED; - this.finalStatus(); + this.finalStatus(); } } @@ -280,7 +281,7 @@ export class WebSocketManager { obj.data = data; } } - + // 检查状态 中间状态,最终失败状态,最终成功状态 checkStatus(reconnect: number): void { // @ts-ignore @@ -331,4 +332,16 @@ export class WebSocketManager { }, // 重连 }; } + // 汇编、源码展开接口回调函数 + // @ts-ignore + webSocketCallBack = async (cmd: number, result: Uint8Array): unknown => { + const decoder = new TextDecoder(); + const jsonString = decoder.decode(result); + let jsonRes = JSON.parse(jsonString); + if (cmd === Constants.DISASSEMBLY_SAVE_BACK_CMD) { + return + }else if (cmd === Constants.DISASSEMBLY_QUERY_BACK_CMD) { + return + } + } } -- Gitee From 778ee789e062cfa146607e9c5d39fbf889b96ab4 Mon Sep 17 00:00:00 2001 From: liufei Date: Fri, 6 Dec 2024 11:09:15 +0800 Subject: [PATCH 03/13] =?UTF-8?q?feat:hiperf=5Fso=E7=82=B9=E5=87=BBfunc?= =?UTF-8?q?=E8=8E=B7=E5=BE=97vaddr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 19 +++ .../logic-worker/ProcedureLogicWorkerPerf.ts | 112 ++++++++++++++++-- 2 files changed, 122 insertions(+), 9 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index e7595dc25..34e8a7fbd 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -65,6 +65,8 @@ export class TabPanePerfAnalysis extends BaseElement { private isComplete: boolean = true; private currentSelectionParam: SelectionParam | undefined | null; static tabLoadingList: Array = []; + private vaddrList: Array = []; + private clickFuncVaddrList: Array = []; set data(val: SelectionParam) { if (val === this.currentSelection) { @@ -204,6 +206,7 @@ export class TabPanePerfAnalysis extends BaseElement { this.addRowClickEventListener(this.perfTableProcess!, this.perfProcessLevelClickEvent.bind(this)); this.addRowClickEventListener(this.perfTableThread!, this.perfThreadLevelClickEvent.bind(this)); this.addRowClickEventListener(this.perfTableSo!, this.perfSoLevelClickEvent.bind(this)); + this.addRowClickEventListener(this.tableFunction!, this.functionClickEvent.bind(this)); } private addRowClickEventListener(table: LitTable, clickEvent: Function): void { @@ -561,6 +564,13 @@ export class TabPanePerfAnalysis extends BaseElement { this.perfAnalysisPie?.hideTip(); } + private functionClickEvent(it: unknown) { + this.clickFuncVaddrList = this.vaddrList.filter((item: unknown) => { + // @ts-ignore + return item.symbolName === it.tableName + }) + } + private sortByColumn(): void { let currentTable: LitTable | null | undefined; switch (this.currentLevel) { @@ -1117,6 +1127,15 @@ export class TabPanePerfAnalysis extends BaseElement { TabPanePerfAnalysis.tabLoadingList.shift(); } }); + const args = [ + { + funcName: 'getVaddrToFile', + funcArgs: [val], + }, + ]; + procedurePool.submitWithName('logic0', 'perf-vaddr', args, undefined, (results: Array) => { + this.vaddrList = results; + }) } private getDataByWorker(val: SelectionParam, handler: Function): void { diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 7ff0957a6..8f2a0d843 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -111,6 +111,12 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { case 'perf-action': this.perfAction(data); break; + case 'perf-vaddr-back': + this.rebackVaddrList(data); + break; + case 'perf-vaddr': + this.perfGetVaddr(data); + break; case 'perf-reset': this.perfReset(); break; @@ -283,6 +289,37 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { this.isAnalysis = false; } } + + rebackVaddrList(data: unknown) { + // @ts-ignore + let vaddrCallchainList = convertJSON(data.params.list); + let sampleCallChainList: unknown = []; + for (let i = 0; i < vaddrCallchainList.length; i++) { + let funcVaddrLastItem = {}; + // @ts-ignore + let callChains = [...this.callChainData[vaddrCallchainList[i].callchain_id]]; + const lastCallChain = callChains[callChains.length - 1]; + // @ts-ignore + funcVaddrLastItem.callchain_id = lastCallChain.sampleId; + // @ts-ignore + funcVaddrLastItem.symbolName = this.dataCache.dataDict.get(lastCallChain.name as number); + // @ts-ignore + funcVaddrLastItem.vaddrInFile = lastCallChain.vaddrInFile; + // @ts-ignore + funcVaddrLastItem.offsetToVaddr = lastCallChain.offsetToVaddr; + // @ts-ignores + sampleCallChainList.push(funcVaddrLastItem); + } + + self.postMessage({ + //@ts-ignore + id: data.id, + //@ts-ignore + action: data.action, + results: sampleCallChainList, + }); + } + private perfAction(data: unknown): void { //@ts-ignore const params = data.params; @@ -312,6 +349,17 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { } } + private perfGetVaddr(data: unknown) { + // @ts-ignore + const params = data.params; + this.backVaddrData(data) + } + + backVaddrData(data: unknown) { + // @ts-ignore + this.handleDataByFuncName(data.params[0].funcName, data.params[0].funcArgs); + } + private perfReset(): void { this.isHideThread = false; this.isHideThreadState = false; @@ -1158,6 +1206,47 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { } } + private queryVaddrToFile(funcArgs: unknown[]): void { + if (funcArgs[1]) { + let sql = ''; + //@ts-ignore + if (funcArgs[1].processId !== undefined) { + //@ts-ignore + sql += `and thread.process_id = ${funcArgs[1].processId}`; + } + //@ts-ignore + if (funcArgs[1].threadId !== undefined) { + //@ts-ignore + sql += ` and s.thread_id = ${funcArgs[1].threadId}`; + } + //@ts-ignore + this.getVaddrToFile(funcArgs[0], sql); + } else { + //@ts-ignore + this.getVaddrToFile(funcArgs[0]); + } + } + + private getVaddrToFile(selectionParam: SelectionParam, sql?: string): void { + let filterSql = this.setFilterSql(selectionParam, sql); + this.queryData( + this.currentEventId, + 'perf-vaddr-back', + `select s.callchain_id + from perf_sample s, trace_range t + where timestamp_trace between ${selectionParam.leftNs} + t.start_ts + and ${selectionParam.rightNs} + t.start_ts + and s.callchain_id != -1 + and s.thread_id != 0 ${filterSql} + group by s.callchain_id`, + { + $startTime: selectionParam.leftNs, + $endTime: selectionParam.rightNs, + $sql: filterSql, + } + ); + } + private handleDataByFuncName(funcName: string, funcArgs: unknown[]): unknown { let result; switch (funcName) { @@ -1172,6 +1261,11 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { break; case 'getCurrentDataFromDbBottomUp': this.queryDataFromDb(funcArgs, 'perf-bottomUp'); + case 'getCurrentDataFromDb': + this.queryDataFromDb(funcArgs); + break; + case 'getVaddrToFile': + this.queryVaddrToFile(funcArgs); break; case 'hideSystemLibrary': this.hideSystemLibrary(); @@ -1207,7 +1301,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { case 'setSearchValue': this.searchValue = funcArgs[0] as string; break; - + case 'combineAnalysisCallChain': result = this.combineCallChainForAnalysis(); break; @@ -1430,7 +1524,7 @@ export class PerfCallChain { sampleId: number = 0; callChainId: number = 0; vaddrInFile: number = 0; - offsetToVaddr:number = 0; + offsetToVaddr: number = 0; tid: number = 0; pid: number = 0; name: number | string = 0; @@ -1504,7 +1598,7 @@ export class PerfCallChainMerageData extends ChartStruct { initChildren: PerfCallChainMerageData[] = []; type: number = 0; vaddrInFile: number = 0; - offsetToVaddr:number = 0; + offsetToVaddr: number = 0; isSelected: boolean = false; searchShow: boolean = true; isSearch: boolean = false; @@ -1612,9 +1706,9 @@ export class PerfCmdLine { class PerfAnalysisSample extends PerfCountSample { threadName: string; - depth:number; - vaddr_in_file:number; - offset_to_vaddr:number; + depth: number; + vaddr_in_file: number; + offset_to_vaddr: number; processName: string; libId: number; libName: string; @@ -1623,9 +1717,9 @@ class PerfAnalysisSample extends PerfCountSample { constructor( threadName: string, - depth:number, - vaddr_in_file:number, - offset_to_vaddr:number, + depth: number, + vaddr_in_file: number, + offset_to_vaddr: number, processName: string, libId: number, libName: string, -- Gitee From e47a0db75e5c26e8678f7f9adae1d6655f653a33 Mon Sep 17 00:00:00 2001 From: liufei Date: Sat, 7 Dec 2024 13:57:35 +0800 Subject: [PATCH 04/13] =?UTF-8?q?feat:=E7=82=B9=E5=87=BB=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=AF=B9=E5=BA=94vaddr=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E3=80=81=E7=BA=BF=E7=A8=8B=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 17 ++++++++++++++++- .../logic-worker/ProcedureLogicWorkerPerf.ts | 13 +++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 34e8a7fbd..8b370d574 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -66,6 +66,9 @@ export class TabPanePerfAnalysis extends BaseElement { private currentSelectionParam: SelectionParam | undefined | null; static tabLoadingList: Array = []; private vaddrList: Array = []; + private selectedTabProcessId: number = 0; + private selectedTabThreadId: number = 0; + private selectedTabfileName: string = ''; private clickFuncVaddrList: Array = []; set data(val: SelectionParam) { @@ -409,6 +412,8 @@ export class TabPanePerfAnalysis extends BaseElement { // @ts-ignore this.processName = it.tableName; this.perfAnalysisPie?.hideTip(); + // @ts-ignore + this.selectedTabProcessId = it.pid; } private threadPieChart(val: SelectionParam): void { @@ -480,6 +485,8 @@ export class TabPanePerfAnalysis extends BaseElement { // @ts-ignore this.threadName = it.tableName; this.perfAnalysisPie?.hideTip(); + // @ts-ignore + this.selectedTabThreadId = it.tid; } private initPerfAnalysisPieConfig(): void { @@ -562,12 +569,20 @@ export class TabPanePerfAnalysis extends BaseElement { } this.titleEl!.textContent = title; this.perfAnalysisPie?.hideTip(); + // @ts-ignore + this.selectedTabfileName = it.tableName; } private functionClickEvent(it: unknown) { this.clickFuncVaddrList = this.vaddrList.filter((item: unknown) => { // @ts-ignore - return item.symbolName === it.tableName + return item.process_id === this.selectedTabProcessId && + // @ts-ignore + item.thread_id === this.selectedTabThreadId && + // @ts-ignore + item.libName === this.selectedTabfileName && + // @ts-ignore + item.symbolName === it.tableName }) } diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 8f2a0d843..21438ebf7 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -307,7 +307,13 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { funcVaddrLastItem.vaddrInFile = lastCallChain.vaddrInFile; // @ts-ignore funcVaddrLastItem.offsetToVaddr = lastCallChain.offsetToVaddr; - // @ts-ignores + // @ts-ignore + funcVaddrLastItem.process_id = vaddrCallchainList[i].process_id; + // @ts-ignore + funcVaddrLastItem.thread_id = vaddrCallchainList[i].thread_id; + // @ts-ignore + funcVaddrLastItem.libName = lastCallChain.fileName; + // @ts-ignore sampleCallChainList.push(funcVaddrLastItem); } @@ -1232,8 +1238,11 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { this.queryData( this.currentEventId, 'perf-vaddr-back', - `select s.callchain_id + `select s.callchain_id, + s.thread_id, + thread.process_id from perf_sample s, trace_range t + left join perf_thread thread on s.thread_id = thread.thread_id where timestamp_trace between ${selectionParam.leftNs} + t.start_ts and ${selectionParam.rightNs} + t.start_ts and s.callchain_id != -1 -- Gitee From fe06a2c377d082adaa0a867829f4806852f82652 Mon Sep 17 00:00:00 2001 From: z30061262 Date: Fri, 6 Dec 2024 12:47:40 +0800 Subject: [PATCH 05/13] =?UTF-8?q?so=E3=80=81an=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=97=B6=E5=8F=91=E9=80=81=E5=88=B0=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhuheng --- .../trace/component/trace/base/TraceSheet.ts | 141 +++++++++++++++--- ide/src/trace/database/SqlLiteWorker.ts | 84 +---------- ide/src/trace/database/TraceWorker.ts | 30 ---- ide/src/webSocket/WebSocketManager.ts | 71 ++++++--- 4 files changed, 175 insertions(+), 151 deletions(-) diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index aa58824fc..f3032a697 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -103,6 +103,9 @@ import { XpowerThreadInfoStruct } from '../../../database/ui-worker/ProcedureWor import { TabPaneXpowerThreadInfoSelection } from '../sheet/xpower/TabPaneXpowerThreadInfoSelection'; import { TabPaneXpowerGpuFreqSelection } from '../sheet/xpower/TabPaneXpowerGpuFreqSelection'; import { XpowerGpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerGpuFreq'; +import {WebSocketManager} from "../../../../webSocket/WebSocketManager"; +import {Constants, TypeConstants} from "../../../../webSocket/Constants"; +import {SpStatisticsHttpUtil} from "../../../../statistics/util/SpStatisticsHttpUtil"; @element('trace-sheet') export class TraceSheet extends BaseElement { @@ -127,6 +130,9 @@ export class TraceSheet extends BaseElement { private optionsDiv: LitPopover | undefined | null; private optionsSettingTree: LitTree | undefined | null; private tabPaneHeight: string = ''; + private enc = new TextEncoder(); + private dec = new TextDecoder(); + private REQ_BUF_SIZE = 4 * 1024 * 1024; static get observedAttributes(): string[] { return ['mode']; @@ -547,7 +553,7 @@ export class TraceSheet extends BaseElement { private importClickEvent(): void { let importFileBt: HTMLInputElement | undefined | null = - this.shadowRoot?.querySelector('#import-file'); + this.shadowRoot?.querySelector('#import-file'); importFileBt!.addEventListener('change', (event): void => { let files = importFileBt?.files; if (files) { @@ -558,30 +564,129 @@ export class TraceSheet extends BaseElement { if (fileList.length > 0) { importFileBt!.disabled = true; window.publish(window.SmartEvent.UI.Loading, { loading: true, text: 'Import So File' }); - threadPool.submit( - 'upload-so', - '', - fileList, - (res: unknown) => { - importFileBt!.disabled = false; // @ts-ignore - if (res.result === 'ok') { - window.publish(window.SmartEvent.UI.UploadSOFile, {}); - } else { - // @ts-ignore - const failedList = res.failedArray.join(','); - window.publish(window.SmartEvent.UI.Error, `parse so file ${failedList} failed!`); - } - }, - 'upload-so' - ); + this.uploadSoOrAN(fileList).then(r => + threadPool.submit( + 'upload-so', + '', + fileList, + (res: unknown) => { + importFileBt!.disabled = false; // @ts-ignore + if (res.result === 'ok') { + window.publish(window.SmartEvent.UI.UploadSOFile, {}); + } else { + // @ts-ignore + const failedList = res.failedArray.join(','); + window.publish(window.SmartEvent.UI.Error, `parse so file ${failedList} failed!`); + } + }, + 'upload-so' + )).finally(() => { + fileList.length = 0; + }) } - fileList.length = 0; } importFileBt!.files = null; importFileBt!.value = ''; }); } + private async uploadSoOrAN(fileList: Array): Promise { + if (fileList) { + fileList.sort((a, b) => b.size - a.size); + await this.uploadAllFiles(fileList); + } + } + + + // 上传文件 + private async uploadAllFiles(fileList: Array): Promise { + // 创建一个副本,避免修改原始的 fileList + const filesToUpload = [...fileList]; + + for (let i = 0; i < filesToUpload.length; i++) { + const file = filesToUpload[i]; + try { + await this.uploadSingleFile(file); + console.log('File ${file.name} uploaded successfully.'); + } catch (error) { + console.error('Failed to upload file: ${file.name}, error'); + } + } + console.log("All files have been uploaded."); + } + + + private uploadSingleFile = async (file: File | null): Promise => { + if (file) { + let writeSize = 0; + let wsInstance = WebSocketManager.getInstance(); + const fileName = file.name; + let bufferIndex = 0; + + // 定义一个 ACK 回调函数的等待机制 + const waitForAck = (): Promise => { + return new Promise((resolve, reject) => { + wsInstance!.registerCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); + // 定义超时定时器 + const timeout = setTimeout(() => { + // 超时后注销回调并拒绝 Promise + wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); + reject(new Error('等待 ACK 超时:文件 ${fileName},索引 ${bufferIndex})')); + }, 10000); + function onAckReceived(cmd: number, result: Uint8Array) { + const decoder = new TextDecoder(); + const jsonString = decoder.decode(result); + let jsonRes = JSON.parse(jsonString); + if (cmd === Constants.DISASSEMBLY_SAVE_BACK_CMD) { + if (jsonRes.fileName === fileName && jsonRes.bufferIndex === bufferIndex) { + wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived) + clearTimeout(timeout); + if (jsonRes.resultCode == 0) { + console.log('ACK received for file: ${jsonRes.fileName}, index: ${jsonRes.bufferIndex}'); + bufferIndex++; + // 当收到对应分片的 ACK 时,resolve Promise,继续上传下一个分片 + resolve(); + }else{ + // 上传失败,拒绝 Promise 并返回 + reject(new Error('Upload failed for file: ${fileName}, index: ${jsonRes.bufferIndex})')); + } + } + } + } + }); + }; + + while (writeSize < file.size) { + let sliceLen = Math.min(file.size - writeSize, this.REQ_BUF_SIZE); + let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); + let buffer: ArrayBuffer | null = await blob.arrayBuffer(); + let data: Uint8Array | null = new Uint8Array(buffer); + + const dataObject = { + file_name: fileName, + buffer_index: bufferIndex, + buffer_size: sliceLen, + total_size: file.size, + is_last: writeSize + sliceLen >= file.size, + buffer: Array.from(data), + }; + + + const dataString = JSON.stringify(dataObject); + const textEncoder = new TextEncoder(); + const encodedData = textEncoder.encode(dataString); + wsInstance!.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); + writeSize += sliceLen; + // 等待服务器端确认当前分片的 ACK + await waitForAck(); + data = null; + buffer = null; + blob = null; + } + console.log('Upload complete for file: ${fileName}'); + } + }; + private exportClickEvent(): void { this.exportBt!.onclick = (): void => { let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!); diff --git a/ide/src/trace/database/SqlLiteWorker.ts b/ide/src/trace/database/SqlLiteWorker.ts index 3560a0e22..673cc414f 100644 --- a/ide/src/trace/database/SqlLiteWorker.ts +++ b/ide/src/trace/database/SqlLiteWorker.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +importScripts('sql-wasm.js'); +// @ts-ignore import {WebSocketManager} from "../../webSocket/WebSocketManager"; importScripts('sql-wasm.js'); @@ -20,7 +22,6 @@ importScripts('sql-wasm.js'); import { temp_init_sql_list } from './TempSql'; import { execProtoForWorker } from './data-trafic/utils/ExecProtoForWorker'; import { TraficEnum } from './data-trafic/utils/QueryEnum'; -import {Constants, TypeConstants} from "../../webSocket/Constants"; let conn: unknown = null; let enc = new TextEncoder(); @@ -113,89 +114,10 @@ function onmessageByUploadSoAction(e: unknown): void { // @ts-ignore uploadSoActionId = e.data.id; // @ts-ignore - const fileList = e.data.params as Array; - const file = fileList[0]; const result = 'ok'; - if (fileList) { - fileList.sort((a, b) => b.size - a.size); - uploadAllFilesRecursively(fileList); - } self.postMessage({ id: uploadSoActionId, action: 'upload-so', results: { result: result, failedArray: failedArray }, }); -} - -// 递归上传文件 -function uploadAllFilesRecursively(fileList: Array): void { - if (fileList.length === 0) { - console.log("All files have been uploaded."); - return; // 所有文件上传完成 - } - - // 上传第一个文件 - const file = fileList[0]; - uploadSoFile(file).then(() => { - console.log(`File ${file.name} uploaded successfully.`); - // 删除数组中的第一个元素 - fileList.shift(); - // 递归调用上传下一个文件 - uploadAllFilesRecursively(fileList); - }).catch((error) => { - console.error(`Failed to upload file: ${file.name}`, error); - // 继续上传下一个,即使失败也继续 - fileList.shift(); - uploadAllFilesRecursively(fileList); - }); -} - - -const uploadSoFile = async (file: File | null): Promise => { - if (file) { - let fileNameBuffer: Uint8Array | null = enc.encode(file.webkitRelativePath); - let fileNameLength = fileNameBuffer.length; - let writeSize = 0; - let wsInstance = WebSocketManager.getInstance() - const fileName = file.name; - let bufferIndex = 0; - while (writeSize < file.size) { - let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE); - let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); - let buffer: ArrayBuffer | null = await blob.arrayBuffer(); - let data: Uint8Array | null = new Uint8Array(buffer); - let fileTotalSize = file.size; - writeSize += sliceLen; - //@ts-ignore - if (wsInstance) { - // 构造包含元数据和文件内容的对象 - const dataObject = { - file_name: fileName, - buffer_index: bufferIndex, - buffer_size: sliceLen, - total_size: fileTotalSize, - is_last: writeSize >= file.size, - buffer: Array.from(data), // 将 Uint8Array 转换为普通数组,以便可以序列化为 JSON - }; - - // 将对象序列化为 JSON 字符串 - const dataString = JSON.stringify(dataObject); - - // 使用 TextEncoder 将字符串编码为 Uint8Array - const textEncoder = new TextEncoder(); - const encodedData = textEncoder.encode(dataString); - - // 通过 WebSocket 发送数据 - wsInstance.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); - } - - // 更新当前片段索引 - bufferIndex++; - data = null; - buffer = null; - blob = null; - } - file = null; - fileNameBuffer = null; - } -}; +} \ No newline at end of file diff --git a/ide/src/trace/database/TraceWorker.ts b/ide/src/trace/database/TraceWorker.ts index 18f3937e0..1923ed8af 100644 --- a/ide/src/trace/database/TraceWorker.ts +++ b/ide/src/trace/database/TraceWorker.ts @@ -13,8 +13,6 @@ * limitations under the License. */ -import {WebSocketManager} from "../../webSocket/WebSocketManager"; - importScripts('trace_streamer_builtin.js'); import { execProtoForWorker } from './data-trafic/utils/ExecProtoForWorker'; import { QueryEnum, TraficEnum } from './data-trafic/utils/QueryEnum'; @@ -22,7 +20,6 @@ import { QueryEnum, TraficEnum } from './data-trafic/utils/QueryEnum'; import { temp_init_sql_list } from './TempSql'; // @ts-ignore import { BatchSphData } from '../proto/SphBaseData'; -import {Constants, TypeConstants} from "../../webSocket/Constants"; enum TsLogLevel { DEBUG = 0, @@ -1331,9 +1328,6 @@ const uploadSoFile = async (file: File | null): Promise => { wasmModule.HEAPU8.set(fileNameBuffer, addr); let writeSize = 0; let upRes = -1; - let wsInstance = WebSocketManager.getInstance() - const fileName = file.name; - let bufferIndex = 0; while (writeSize < file.size) { let sliceLen = Math.min(file.size - writeSize, REQ_BUF_SIZE); let blob: Blob | null = file.slice(writeSize, writeSize + sliceLen); @@ -1345,30 +1339,6 @@ const uploadSoFile = async (file: File | null): Promise => { writeSize += sliceLen; //@ts-ignore upRes = wasmModule._TraceStreamerDownloadELFEx(size, fileNameLength, sliceLen, 1); - if (wsInstance) { - // 构造包含元数据和文件内容的对象 - const dataObject = { - file_name: fileName, - buffer_index: bufferIndex, - buffer_size: sliceLen, - total_size: size, - is_last: writeSize >= file.size, - buffer: Array.from(data), // 将 Uint8Array 转换为普通数组,以便可以序列化为 JSON - }; - - // 将对象序列化为 JSON 字符串 - const dataString = JSON.stringify(dataObject); - - // 使用 TextEncoder 将字符串编码为 Uint8Array - const textEncoder = new TextEncoder(); - const encodedData = textEncoder.encode(dataString); - - // 通过 WebSocket 发送数据 - wsInstance.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_SAVE_CMD, encodedData); - } - - // 更新当前片段索引 - bufferIndex++; data = null; buffer = null; blob = null; diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index 76620233b..a9d22d20e 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -34,7 +34,7 @@ export class WebSocketManager { static instance: WebSocketManager | null | undefined = null; url: string = `ws://localhost:${Constants.NODE_PORT}`; private websocket: WebSocket | null | undefined = null; - private distributeMap: Map = new Map(); + private distributeMap: Map = new Map(); private sessionId: number | null | undefined; private session: bigint | null | undefined; private heartbeatInterval: number | null | undefined; @@ -83,7 +83,6 @@ export class WebSocketManager { this.initLoginInfo(); this.clearHeartbeat(); }; - WebSocketManager.getInstance()!.registerMessageListener(TypeConstants.DISASSEMBLY_TYPE, this.webSocketCallBack, () => {}); } /** @@ -140,7 +139,13 @@ export class WebSocketManager { // 业务 businessMessage(decode: MessageParam): void { - this.distributeMap.get(decode.type!)?.messageCallback(decode.cmd, decode.data); + if (this.distributeMap.has(decode.type!)){ + const callbackObj = this.distributeMap.get(decode.type!)!; + // 遍历调用所有 eventCallBacks + callbackObj.messageCallbacks.forEach(callback => { + callback(decode.cmd, decode.data); + }); + } } // get版本 @@ -209,7 +214,35 @@ export class WebSocketManager { */ registerMessageListener(type: number, callback: Function, eventCallBack: Function): void { if (!this.distributeMap.has(type)) { - this.distributeMap.set(type, { 'messageCallback': callback, 'eventCallBack': eventCallBack }); + this.distributeMap.set(type, { 'messageCallbacks': [], 'eventCallBack': eventCallBack }); + } + const callbackObj = this.distributeMap.get(type)!; + callbackObj.messageCallbacks.push(callback); + } + + // 注册回调函数 + registerCallback(type: number, callback: Function): void { + if (!this.distributeMap.has(type)) { + this.distributeMap.set(type, { 'messageCallbacks': [], 'eventCallBack': () => {} }); + } + const callbackObj = this.distributeMap.get(type)!; + callbackObj.messageCallbacks.push(callback); + } + + // 删除回调函数 + unregisterCallback(type: number, callback: Function): void { + if (!this.distributeMap.has(type)) { + return; + } + // 获取指定类型的回调对象 + const callbackObj = this.distributeMap.get(type)!; + + // 在回调数组中查找并移除与传入的回调函数匹配的项 + callbackObj.messageCallbacks = callbackObj.messageCallbacks.filter((cb) => cb !== callback); + + // 如果回调数组为空,同时 eventCallBack 也为空,则可以删除整个类型 + if (callbackObj.messageCallbacks.length === 0 && !callbackObj.eventCallBack) { + this.distributeMap.delete(type); } } @@ -283,14 +316,20 @@ export class WebSocketManager { } // 检查状态 中间状态,最终失败状态,最终成功状态 - checkStatus(reconnect: number): void { + checkStatus(type: number): void { // 更改参数名称为 type,以反映实际传递的值 // @ts-ignore let statuses = this.getStatusesPrompt()[this.status]; - if (statuses.type === INTERMEDIATE_STATE) { - this.distributeMap.get(reconnect)!.eventCallBack(this.status); - } else if (statuses.type === FAILED_STATE) { - this.reconnect = reconnect; - this.connectWebSocket(); + const distributeEntry = this.distributeMap.get(type); + + if (distributeEntry && typeof distributeEntry.eventCallBack === 'function') { + if (statuses.type === INTERMEDIATE_STATE) { + distributeEntry.eventCallBack(this.status); + } else if (statuses.type === FAILED_STATE) { + this.reconnect = type; // 确认这是您想要的逻辑 + this.connectWebSocket(); + } + } else { + console.error('No valid eventCallBack found for type: ${type}'); } } @@ -332,16 +371,4 @@ export class WebSocketManager { }, // 重连 }; } - // 汇编、源码展开接口回调函数 - // @ts-ignore - webSocketCallBack = async (cmd: number, result: Uint8Array): unknown => { - const decoder = new TextDecoder(); - const jsonString = decoder.decode(result); - let jsonRes = JSON.parse(jsonString); - if (cmd === Constants.DISASSEMBLY_SAVE_BACK_CMD) { - return - }else if (cmd === Constants.DISASSEMBLY_QUERY_BACK_CMD) { - return - } - } } -- Gitee From 31769fa3100720146df9268ad39f84f7420198ec Mon Sep 17 00:00:00 2001 From: luobinghao Date: Mon, 9 Dec 2024 16:00:34 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E6=96=B0=E5=A2=9Efunc=20=E6=B1=87?= =?UTF-8?q?=E7=BC=96=E5=88=86=E6=9E=90=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: luobinghao --- ide/src/trace/bean/PerfAnalysis.ts | 37 +++++ .../trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 61 ++++++++ .../trace/sheet/hiperf/TabPerfFuncAsm.ts | 142 ++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 ide/src/trace/bean/PerfAnalysis.ts create mode 100644 ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts create mode 100644 ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts diff --git a/ide/src/trace/bean/PerfAnalysis.ts b/ide/src/trace/bean/PerfAnalysis.ts new file mode 100644 index 000000000..6ca9673df --- /dev/null +++ b/ide/src/trace/bean/PerfAnalysis.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class PerfFunctionAsmStruct { + totalCount: number = 0; + functionName: string = ''; +} + +export class PerfFunctionSelfCountPerAssembler { + addr: number = 0; + selfcount: number = 0; +} + +export class AsmInstruction { + addr: number = 0; + instruction: string = ''; +} + +export class PerfFunctionAsmShowUpData { + addr: number = 0; + instruction: string = ''; + selfCount: number = 0; + percent: number = 0; +} + diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts new file mode 100644 index 000000000..162497b59 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const TabPerfFuncAsmHtml = ` + +
+
+
+
Function Name:
+
Total Count:
+
+ + + + + + + +
+
+`; diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts new file mode 100644 index 000000000..a326fb6b2 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -0,0 +1,142 @@ +import { TabPerfFuncAsmHtml } from "./TabPerfFuncAsm.html"; +import { BaseElement, element } from "../../../../../base-ui/BaseElement"; +import { LitTable } from "../../../../../base-ui/table/lit-table"; +import { + AsmInstruction, + PerfFunctionAsmShowUpData, + PerfFunctionAsmStruct, + PerfFunctionSelfCountPerAssembler, +} from "../../../../bean/PerfAnalysis"; + +@element("tab-perf-func-asm") +export class TabPerfFuncAsm extends BaseElement { + private assmblerTable: LitTable | null | undefined; + private loadingElement: HTMLElement | null | undefined; + private functionName: string = ""; + private totalCount: number = 0; + private functionNameElement: HTMLDivElement | null | undefined; + private totalCountElement: HTMLDivElement | null | undefined; + private functionSelfCountPerAssembler: PerfFunctionSelfCountPerAssembler[] = + []; + private asmInstruction: AsmInstruction[] = []; + private showUpData: PerfFunctionAsmShowUpData[] = []; + private originalShowUpData: PerfFunctionAsmShowUpData[] = []; + + initHtml(): string { + return TabPerfFuncAsmHtml; + } + + initElements(): void { + this.assmblerTable = this.shadowRoot!.querySelector( + "#perf-function-asm-table" + ); + this.loadingElement = + this.shadowRoot!.querySelector("#loading"); + this.functionNameElement = + this.shadowRoot!.querySelector("#function-name"); + this.totalCountElement = + this.shadowRoot!.querySelector("#total-count"); + this.assmblerTable!.style.display = "grid"; + + this.assmblerTable!.itemTextHandleMap.set("addr", (value: unknown) => { + return `0x${(value as number).toString(16)}`; + }); + + this.assmblerTable!.itemTextHandleMap.set("selfCount", (value: unknown) => { + return (value as number) === 0 ? "" : (value as number).toString(); + }); + + this.assmblerTable!.itemTextHandleMap.set("percent", (value: unknown) => { + return (value as number) === 0 ? "" : (value as number).toString(); + }); + + this.assmblerTable!.addEventListener("column-click", ((evt: Event) => { + const { key, sort } = (evt as CustomEvent).detail; + if (key === "selfCount") { + if (sort === 0) { + this.resetSort(); + } else { + this.showUpData.sort((a, b) => { + return sort === 1 + ? a.selfCount - b.selfCount + : b.selfCount - a.selfCount; + }); + this.refreshFunctionAsmData(); + } + } else if (key === "percent") { + if (sort === 0) { + this.resetSort(); + } else { + this.showUpData.sort((a, b) => { + return sort === 1 ? a.percent - b.percent : b.percent - a.percent; + }); + this.refreshFunctionAsmData(); + } + } + }) as EventListener); + } + + private updateTitle(): void { + if (this.functionName) { + this.functionNameElement!.innerHTML = `Function Name: ${this.functionName}`; + this.totalCountElement!.innerHTML = `Total Count: ${this.totalCount}`; + } + } + + private showLoading(): void { + if (this.loadingElement) { + this.loadingElement.removeAttribute("hidden"); + } + } + + private hideLoading(): void { + if (this.loadingElement) { + this.loadingElement.setAttribute("hidden", ""); + } + } + + set data(data: PerfFunctionAsmStruct) { + this.showUpData = []; + this.refreshFunctionAsmData(); + } + + private calcutelateShowUpData(): void { + const selfCountMap = new Map(); + this.functionSelfCountPerAssembler.forEach((item) => { + selfCountMap.set(item.addr, item.selfcount); + }); + + this.showUpData = this.asmInstruction.map((asmItem: AsmInstruction) => ({ + addr: asmItem.addr, + instruction: asmItem.instruction, + selfCount: selfCountMap.get(asmItem.addr) || 0, + percent: + Math.round( + ((selfCountMap.get(asmItem.addr) || 0) / this.totalCount) * 10000 + ) / 100, + })); + this.originalShowUpData = [...this.showUpData]; + } + + private refreshFunctionAsmData(): void { + this.assmblerTable!.recycleDataSource = this.showUpData; + console.log(this.assmblerTable!.recycleDataSource); + this.assmblerTable!.reMeauseHeight(); + } + + public connectedCallback(): void { + new ResizeObserver(() => { + if (this.assmblerTable && this.parentElement) { + this.assmblerTable.style.height = `${ + this.parentElement.clientHeight - 50 + }px`; + this.assmblerTable.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + private resetSort(): void { + this.showUpData = [...this.originalShowUpData]; + this.refreshFunctionAsmData(); + } +} -- Gitee From 1a8ec2f07023b078d8594bdc434ab844cf822a55 Mon Sep 17 00:00:00 2001 From: yangxiaoshuai2022 Date: Mon, 9 Dec 2024 17:52:11 +0800 Subject: [PATCH 07/13] activate tab-perf-func-asm when click funcRow Signed-off-by: yangxiaoshuai2022 --- .../trace/component/trace/base/TraceSheet.ts | 17 +++++++++++++ .../component/trace/base/TraceSheetConfig.ts | 5 ++++ .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 24 ++++++++++++++++++- .../trace/sheet/hiperf/TabPerfFuncAsm.ts | 14 +++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index f3032a697..3f13e85a3 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -221,6 +221,8 @@ export class TraceSheet extends BaseElement { this.perfAnalysisListener(evt); }); // @ts-ignore + this.getComponentByID('box-perf-analysis')?.addFunctionRowClickEventListener(this.functionAnalysisListener.bind(this)); + // @ts-ignore this.getComponentByID('box-native-statistic-analysis')?.addEventListener('row-click', (e: MouseEvent) => { this.nativeAnalysisListener(e); }); @@ -302,6 +304,21 @@ export class TraceSheet extends BaseElement { } } + private functionAnalysisListener(evt: unknown, vaddrList: Array): void { + // @ts-ignore + this.currentPaneID = 'box-perf-analysis'; + //隐藏除了当前Tab页的其他Tab页 + this.shadowRoot!.querySelectorAll('lit-tabpane').forEach((it): boolean => + it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) + ); + let pane = this.getPaneByID('tab-perf-func-asm');//通过Id找到需要展示的Tab页 + pane.closeable = true; + pane.hidden = false; + this.litTabs!.activeByKey(pane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 + // @ts-ignore + pane.tab = evt.tableName;//设置Tab页标题 + } + private nativeAnalysisListener(e: MouseEvent): void { //@ts-ignore if (e.detail.button === 2 && e.detail.tableName) { diff --git a/ide/src/trace/component/trace/base/TraceSheetConfig.ts b/ide/src/trace/component/trace/base/TraceSheetConfig.ts index dc0204ebf..f3f3c35bc 100644 --- a/ide/src/trace/component/trace/base/TraceSheetConfig.ts +++ b/ide/src/trace/component/trace/base/TraceSheetConfig.ts @@ -151,6 +151,7 @@ import { TabPanePerfAsync } from '../sheet/hiperf/TabPerfAsyncList'; import { TabPaneUserPlugin } from '../sheet/userPlugin/TabPaneUserPlugin'; import { TabPaneDmaFence } from '../sheet/dma-fence/TabPaneDmaFenceSelect'; import { TabPaneSliceChild } from '../sheet/process/TabPaneSliceChild'; +import { TabPerfFuncAsm } from '../sheet/hiperf/TabPerfFuncAsm' export let tabConfig: { [key: string]: { @@ -791,6 +792,10 @@ export let tabConfig: { title: '', type: TabPaneSliceChild, }, + 'tab-perf-func-asm': { + title: '', + type: TabPerfFuncAsm, + }, 'box-xpower-thread-info-selection': { title: 'Thread Info Selection', type: TabPaneXpowerThreadInfoSelection, diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 8b370d574..8e32c3a5c 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -25,6 +25,8 @@ import { LitCheckBox } from '../../../../../base-ui/checkbox/LitCheckBox'; import { initSort } from '../SheetUtils'; import { TabpanePerfProfile } from './TabPerfProfile'; import { TabPanePerfAnalysisHtml } from './TabPanePerfAnalysis.html'; +import { WebSocketManager } from '../../../../../webSocket/WebSocketManager'; +import { Constants, TypeConstants } from '../../../../../webSocket/Constants'; @element('tabpane-perf-analysis') export class TabPanePerfAnalysis extends BaseElement { @@ -70,6 +72,8 @@ export class TabPanePerfAnalysis extends BaseElement { private selectedTabThreadId: number = 0; private selectedTabfileName: string = ''; private clickFuncVaddrList: Array = []; + private functionListener!: Function | undefined | null; + private currentSoName: string = ''; set data(val: SelectionParam) { if (val === this.currentSelection) { @@ -554,6 +558,8 @@ export class TabPanePerfAnalysis extends BaseElement { private perfSoLevelClickEvent(it: unknown): void { this.reset(this.tableFunction!, true); this.showAssignLevel(this.tableFunction!, this.perfTableSo!, 3, this.functionData); + // @ts-ignore + this.currentSoName = it.tableName; this.getHiperfFunction(it); let title = ''; if (this.processName.length > 0) { @@ -584,7 +590,19 @@ export class TabPanePerfAnalysis extends BaseElement { // @ts-ignore item.symbolName === it.tableName }) - } + if (this.clickFuncVaddrList.length > 0) { + const textEncoder = new TextEncoder(); + const queryData = { + elf_name: this.currentSoName, //@ts-ignore + vaddr: this.clickFuncVaddrList[0].vaddrInFile, //@ts-ignore + func: it.tableName + }; + const dataString = JSON.stringify(queryData); + const encodedData = textEncoder.encode(dataString); + WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_CMD, encodedData); + } + this.functionListener!(it, this.clickFuncVaddrList); + } private sortByColumn(): void { let currentTable: LitTable | null | undefined; @@ -1188,6 +1206,10 @@ export class TabPanePerfAnalysis extends BaseElement { }).observe(this.parentElement!); } + public addFunctionRowClickEventListener(clickEvent: Function): void { + this.functionListener = clickEvent; + } + initHtml(): string { return TabPanePerfAnalysisHtml; } diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index a326fb6b2..2ad1d175b 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -7,6 +7,9 @@ import { PerfFunctionAsmStruct, PerfFunctionSelfCountPerAssembler, } from "../../../../bean/PerfAnalysis"; +import { WebSocketManager } from "../../../../../webSocket/WebSocketManager"; +import { ConstructorType } from "../../../../../js-heap/model/UiStruct"; +import { TypeConstants } from "../../../../../webSocket/Constants"; @element("tab-perf-func-asm") export class TabPerfFuncAsm extends BaseElement { @@ -21,6 +24,7 @@ export class TabPerfFuncAsm extends BaseElement { private asmInstruction: AsmInstruction[] = []; private showUpData: PerfFunctionAsmShowUpData[] = []; private originalShowUpData: PerfFunctionAsmShowUpData[] = []; + private currentAsmList: Array = []; initHtml(): string { return TabPerfFuncAsmHtml; @@ -74,6 +78,16 @@ export class TabPerfFuncAsm extends BaseElement { } } }) as EventListener); + // 注册汇编代码请求回调函数 + WebSocketManager.getInstance()?.registerCallback(TypeConstants.DISASSEMBLY_TYPE, this.receiveAsmData.bind(this)); + } + + private receiveAsmData(cmd: unknown, e: unknown): void { + // @ts-ignore + const result = JSON.parse(new TextDecoder().decode(e)); + if (result.resultCode === 0) { + this.currentAsmList = JSON.parse(result.resultMessage); + } } private updateTitle(): void { -- Gitee From 4bcaabe088b2b10212236d5052d78fa0ae762eaa Mon Sep 17 00:00:00 2001 From: luobinghao Date: Wed, 11 Dec 2024 14:36:03 +0800 Subject: [PATCH 08/13] =?UTF-8?q?function=20=E6=B1=87=E7=BC=96=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: luobinghao --- ide/src/trace/bean/PerfAnalysis.ts | 19 +- .../trace/component/trace/base/TraceSheet.ts | 24 +- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 3 +- .../trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 8 +- .../trace/sheet/hiperf/TabPerfFuncAsm.ts | 213 ++++++++++++++---- 5 files changed, 205 insertions(+), 62 deletions(-) diff --git a/ide/src/trace/bean/PerfAnalysis.ts b/ide/src/trace/bean/PerfAnalysis.ts index 6ca9673df..abe0cf25d 100644 --- a/ide/src/trace/bean/PerfAnalysis.ts +++ b/ide/src/trace/bean/PerfAnalysis.ts @@ -13,21 +13,24 @@ * limitations under the License. */ -export class PerfFunctionAsmStruct { +export class PerfFunctionAsmParam { totalCount: number = 0; - functionName: string = ''; + functionName: string = ""; + vaddrList: Array = []; } -export class PerfFunctionSelfCountPerAssembler { - addr: number = 0; - selfcount: number = 0; -} - -export class AsmInstruction { +export class FormattedAsmInstruction { + selfcount:number = 0; + percent:number = 0; addr: number = 0; instruction: string = ''; } +export class OriginAsmInstruction { + addr:string = ''; + instruction:string = ''; +} + export class PerfFunctionAsmShowUpData { addr: number = 0; instruction: string = ''; diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index 3f13e85a3..15aaa2a3c 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -106,6 +106,8 @@ import { XpowerGpuFreqStruct } from '../../../database/ui-worker/ProcedureWorker import {WebSocketManager} from "../../../../webSocket/WebSocketManager"; import {Constants, TypeConstants} from "../../../../webSocket/Constants"; import {SpStatisticsHttpUtil} from "../../../../statistics/util/SpStatisticsHttpUtil"; +import { PerfFunctionAsmParam } from '../../../bean/PerfAnalysis'; +import { TabPerfFuncAsm } from '../sheet/hiperf/TabPerfFuncAsm'; @element('trace-sheet') export class TraceSheet extends BaseElement { @@ -306,17 +308,27 @@ export class TraceSheet extends BaseElement { private functionAnalysisListener(evt: unknown, vaddrList: Array): void { // @ts-ignore - this.currentPaneID = 'box-perf-analysis'; + this.currentPaneID = "box-perf-analysis"; //隐藏除了当前Tab页的其他Tab页 - this.shadowRoot!.querySelectorAll('lit-tabpane').forEach((it): boolean => - it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) + this.shadowRoot!.querySelectorAll("lit-tabpane").forEach( + (it): boolean => + it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) ); - let pane = this.getPaneByID('tab-perf-func-asm');//通过Id找到需要展示的Tab页 + let pane = this.getPaneByID("tab-perf-func-asm"); //通过Id找到需要展示的Tab页 pane.closeable = true; pane.hidden = false; - this.litTabs!.activeByKey(pane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 // @ts-ignore - pane.tab = evt.tableName;//设置Tab页标题 + pane.tab = evt.tableName; //设置Tab页标题 + console.log("lbh: evt", evt); + console.log("lbh: vaadrlist", vaddrList); + let param = new PerfFunctionAsmParam(); + param.vaddrList = vaddrList; + // @ts-ignore + param.functionName = evt.tableName; + // @ts-ignore + param.totalCount = evt.count; + (pane.children.item(0) as TabPerfFuncAsm)!.data = param; + this.litTabs!.activeByKey(pane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 } private nativeAnalysisListener(e: MouseEvent): void { diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 8e32c3a5c..0f04ec693 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -599,10 +599,11 @@ export class TabPanePerfAnalysis extends BaseElement { }; const dataString = JSON.stringify(queryData); const encodedData = textEncoder.encode(dataString); + console.log("lbh: queryData",queryData); WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_CMD, encodedData); } this.functionListener!(it, this.clickFuncVaddrList); - } + } private sortByColumn(): void { let currentTable: LitTable | null | undefined; diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts index 162497b59..f3c2b86ea 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -42,16 +42,22 @@ export const TabPerfFuncAsmHtml = ` left: 50%; transform: translate(-50%, -50%); } +.error-message { + color: red; + margin-top: 5px; + display: none; /* 默认隐藏 */ +}
Function Name:
Total Count:
+
- + diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index 2ad1d175b..c8ff2d33e 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -2,14 +2,12 @@ import { TabPerfFuncAsmHtml } from "./TabPerfFuncAsm.html"; import { BaseElement, element } from "../../../../../base-ui/BaseElement"; import { LitTable } from "../../../../../base-ui/table/lit-table"; import { - AsmInstruction, - PerfFunctionAsmShowUpData, - PerfFunctionAsmStruct, - PerfFunctionSelfCountPerAssembler, + FormattedAsmInstruction, + PerfFunctionAsmParam, + OriginAsmInstruction, } from "../../../../bean/PerfAnalysis"; import { WebSocketManager } from "../../../../../webSocket/WebSocketManager"; -import { ConstructorType } from "../../../../../js-heap/model/UiStruct"; -import { TypeConstants } from "../../../../../webSocket/Constants"; +import { Constants, TypeConstants } from "../../../../../webSocket/Constants"; @element("tab-perf-func-asm") export class TabPerfFuncAsm extends BaseElement { @@ -19,13 +17,14 @@ export class TabPerfFuncAsm extends BaseElement { private totalCount: number = 0; private functionNameElement: HTMLDivElement | null | undefined; private totalCountElement: HTMLDivElement | null | undefined; - private functionSelfCountPerAssembler: PerfFunctionSelfCountPerAssembler[] = - []; - private asmInstruction: AsmInstruction[] = []; - private showUpData: PerfFunctionAsmShowUpData[] = []; - private originalShowUpData: PerfFunctionAsmShowUpData[] = []; + private errorMessageElement: HTMLDivElement | null | undefined; + private funcBaseAddr: bigint = BigInt(0); + // Key: offset; Value: selfcount + private funcSampleMap: Map = new Map(); + private showUpData: FormattedAsmInstruction[] = []; + private originalShowUpData: FormattedAsmInstruction[] = []; private currentAsmList: Array = []; - + private formattedAsmIntructionArray: FormattedAsmInstruction[] = []; initHtml(): string { return TabPerfFuncAsmHtml; } @@ -40,13 +39,14 @@ export class TabPerfFuncAsm extends BaseElement { this.shadowRoot!.querySelector("#function-name"); this.totalCountElement = this.shadowRoot!.querySelector("#total-count"); + this.errorMessageElement = this.shadowRoot!.querySelector("#error-message"); this.assmblerTable!.style.display = "grid"; this.assmblerTable!.itemTextHandleMap.set("addr", (value: unknown) => { return `0x${(value as number).toString(16)}`; }); - this.assmblerTable!.itemTextHandleMap.set("selfCount", (value: unknown) => { + this.assmblerTable!.itemTextHandleMap.set("selfcount", (value: unknown) => { return (value as number) === 0 ? "" : (value as number).toString(); }); @@ -54,27 +54,40 @@ export class TabPerfFuncAsm extends BaseElement { return (value as number) === 0 ? "" : (value as number).toString(); }); + this.assmblerTable!.itemTextHandleMap.set("instruction", (value: unknown) => { + return (value as string) === "" ? "INVALID" : (value as string); + }); + this.assmblerTable!.addEventListener("column-click", ((evt: Event) => { const { key, sort } = (evt as CustomEvent).detail; - if (key === "selfCount") { + console.log("lbh:sort", sort) + if (key === "selfcount") { if (sort === 0) { - this.resetSort(); + console.log("lbh: sort0") + this.assmblerTable!.recycleDataSource = this.originalShowUpData; + console.log("lbh:sort recycle", this.assmblerTable!.recycleDataSource) + console.log("lbh:sort originalShowUpData", this.originalShowUpData) + this.assmblerTable!.reMeauseHeight(); } else { this.showUpData.sort((a, b) => { return sort === 1 - ? a.selfCount - b.selfCount - : b.selfCount - a.selfCount; + ? a.selfcount - b.selfcount + : b.selfcount - a.selfcount; }); - this.refreshFunctionAsmData(); + this.assmblerTable!.recycleDataSource = this.showUpData; + this.assmblerTable!.reMeauseHeight(); } + console.log("after sort: ", this.originalShowUpData) } else if (key === "percent") { if (sort === 0) { - this.resetSort(); + this.assmblerTable!.recycleDataSource = this.originalShowUpData; + this.assmblerTable!.reMeauseHeight(); } else { this.showUpData.sort((a, b) => { return sort === 1 ? a.percent - b.percent : b.percent - a.percent; }); - this.refreshFunctionAsmData(); + this.assmblerTable!.recycleDataSource = this.showUpData; + this.assmblerTable!.reMeauseHeight(); } } }) as EventListener); @@ -95,6 +108,7 @@ export class TabPerfFuncAsm extends BaseElement { this.functionNameElement!.innerHTML = `Function Name: ${this.functionName}`; this.totalCountElement!.innerHTML = `Total Count: ${this.totalCount}`; } + console.log(this.totalCount) } private showLoading(): void { @@ -109,33 +123,145 @@ export class TabPerfFuncAsm extends BaseElement { } } - set data(data: PerfFunctionAsmStruct) { - this.showUpData = []; - this.refreshFunctionAsmData(); + private showError(message: string): void { + if (this.errorMessageElement) { + this.errorMessageElement.textContent = message; + this.errorMessageElement.style.display = 'block'; + } } - private calcutelateShowUpData(): void { - const selfCountMap = new Map(); - this.functionSelfCountPerAssembler.forEach((item) => { - selfCountMap.set(item.addr, item.selfcount); + private hideError(): void { + if (this.errorMessageElement) { + this.errorMessageElement.style.display = 'none'; + } + } + + set data(data: PerfFunctionAsmParam) { + if (this.functionName === data.functionName) { + return; + } + + (async () => { + try { + this.clearData(); + this.functionName = data.functionName; + this.totalCount = data.totalCount; + this.updateTitle(); + this.showLoading(); + // @ts-ignore + const vaddrInFile = data.vaddrList[0].vaddrInFile; + // 1. 先转成 BigInt + // 2. 用 asUintN 转成无符号64位 + // 3. 如果需要用作数值运算,再转回 Number + this.funcBaseAddr = BigInt.asUintN(64, BigInt(vaddrInFile)); + // 1. 计算采样数据 + this.calculateFuncAsmSapleCount(data.vaddrList); + // 2. 等待汇编指令数据 + let callback: (cmd: number, e: Uint8Array) => void; + + await Promise.race([ + new Promise((resolve, reject) => { + callback = (cmd: number, e: Uint8Array) => { + try { + console.log('Received cmd:', cmd, 'Expected:', Constants.DISASSEMBLY_QUERY_BACK_CMD); + + if (cmd === Constants.DISASSEMBLY_QUERY_BACK_CMD) { + const result = JSON.parse(new TextDecoder().decode(e)); + if (result.resultCode === 0) { + this.formatAsmInstruction(JSON.parse(result.resultMessage)); + this.calcutelateShowUpData(); + resolve(); + } else { + reject(new Error(`Failed with code: ${result.resultCode}`)); + } + } else { + reject(new Error(`Unexpected command: ${cmd}`)); + } + WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); + } catch (error) { + WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); + reject(error); + } + }; + + WebSocketManager.getInstance()?.registerCallback(TypeConstants.DISASSEMBLY_TYPE, callback); + }), + new Promise((_, reject) => setTimeout(() => { + WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); + reject(new Error('Request timeout')); + }, 5000)) + ]); + + // 5. 更新表格 + + } catch (error) { + console.error('Error:', error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + this.showError(`Error: can't get assembly code because ${errorMessage},show sample list without assembly code`); + this.calcutelateErrorShowUpData(); + } finally { + console.log("lbh:finally:originalShowUpData ", this.originalShowUpData) + console.log("lbh:finally:funcBaseAddr ", this.funcBaseAddr) + console.log("lbh:finally:funcSampleMap ", this.funcSampleMap) + this.showUpData = [...this.originalShowUpData]; + this.assmblerTable!.recycleDataSource = this.showUpData; + this.assmblerTable!.reMeauseHeight(); + this.hideLoading(); + } + })(); + } + + private calcutelateErrorShowUpData(): void { + this.funcSampleMap.forEach((selfCount, offsetToVaddr) => { + this.originalShowUpData.push({ + selfcount: selfCount, + percent: Math.round((selfCount / this.totalCount) * 10000) / 100, + // 地址计算也使用 BigInt + addr: Number(BigInt.asUintN(64, this.funcBaseAddr + BigInt(offsetToVaddr))), + instruction: '' + }) + }) + console.log("lbh:calcutelateErrorShowUpData originalShowUpData ", this.originalShowUpData) + console.log("lbh:calcutelateErrorShowUpData funcBaseAddr ", this.funcBaseAddr) + console.log("lbh:calcutelateErrorShowUpData funcSampleMap ", this.funcSampleMap) + } + + private calculateFuncAsmSapleCount(vaddrList: Array): void { + vaddrList.forEach(item => { + // @ts-ignore + const count = this.funcSampleMap.get(item.offsetToVaddr) || 0; + // @ts-ignore + this.funcSampleMap.set(item.offsetToVaddr, count + 1); }); + } - this.showUpData = this.asmInstruction.map((asmItem: AsmInstruction) => ({ - addr: asmItem.addr, - instruction: asmItem.instruction, - selfCount: selfCountMap.get(asmItem.addr) || 0, - percent: - Math.round( - ((selfCountMap.get(asmItem.addr) || 0) / this.totalCount) * 10000 - ) / 100, - })); - this.originalShowUpData = [...this.showUpData]; + private formatAsmInstruction(originAsmInstruction: Array) { + this.formattedAsmIntructionArray = originAsmInstruction.map(instructs => ({ + selfcount: 0, + percent: 0, + addr: parseInt(instructs.addr, 16), + instruction: instructs.instruction, + }) as FormattedAsmInstruction); } - private refreshFunctionAsmData(): void { - this.assmblerTable!.recycleDataSource = this.showUpData; - console.log(this.assmblerTable!.recycleDataSource); - this.assmblerTable!.reMeauseHeight(); + + private clearData(): void { + this.hideError(); + this.funcSampleMap.clear(); + this.showUpData = []; + this.originalShowUpData = []; + this.currentAsmList = []; + this.formattedAsmIntructionArray = []; + this.assmblerTable!.recycleDataSource = []; + } + + private calcutelateShowUpData(): void { + this.funcSampleMap.forEach((selfCount, offsetToVaddr) => { + let instructionPosition = offsetToVaddr / 4; + this.formattedAsmIntructionArray[instructionPosition].selfcount = selfCount; + this.formattedAsmIntructionArray[instructionPosition].percent = Math.round((selfCount / this.totalCount) * 10000) / 100; + }) + this.originalShowUpData = this.formattedAsmIntructionArray; } public connectedCallback(): void { @@ -148,9 +274,4 @@ export class TabPerfFuncAsm extends BaseElement { } }).observe(this.parentElement!); } - - private resetSort(): void { - this.showUpData = [...this.originalShowUpData]; - this.refreshFunctionAsmData(); - } } -- Gitee From 8a40a11fdf22812277f2d33d3fd4ac783bd1b81b Mon Sep 17 00:00:00 2001 From: liufei Date: Thu, 12 Dec 2024 20:11:42 +0800 Subject: [PATCH 09/13] =?UTF-8?q?fix:hiperf=5FsoFunc=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E8=BF=87=E6=BB=A4=E4=BF=AE=E6=94=B9pid,tid=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 0f04ec693..09d10177c 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -68,8 +68,6 @@ export class TabPanePerfAnalysis extends BaseElement { private currentSelectionParam: SelectionParam | undefined | null; static tabLoadingList: Array = []; private vaddrList: Array = []; - private selectedTabProcessId: number = 0; - private selectedTabThreadId: number = 0; private selectedTabfileName: string = ''; private clickFuncVaddrList: Array = []; private functionListener!: Function | undefined | null; @@ -416,8 +414,6 @@ export class TabPanePerfAnalysis extends BaseElement { // @ts-ignore this.processName = it.tableName; this.perfAnalysisPie?.hideTip(); - // @ts-ignore - this.selectedTabProcessId = it.pid; } private threadPieChart(val: SelectionParam): void { @@ -489,8 +485,6 @@ export class TabPanePerfAnalysis extends BaseElement { // @ts-ignore this.threadName = it.tableName; this.perfAnalysisPie?.hideTip(); - // @ts-ignore - this.selectedTabThreadId = it.tid; } private initPerfAnalysisPieConfig(): void { @@ -582,9 +576,9 @@ export class TabPanePerfAnalysis extends BaseElement { private functionClickEvent(it: unknown) { this.clickFuncVaddrList = this.vaddrList.filter((item: unknown) => { // @ts-ignore - return item.process_id === this.selectedTabProcessId && + return item.process_id === it.pid && // @ts-ignore - item.thread_id === this.selectedTabThreadId && + item.thread_id === it.tid && // @ts-ignore item.libName === this.selectedTabfileName && // @ts-ignore @@ -599,7 +593,7 @@ export class TabPanePerfAnalysis extends BaseElement { }; const dataString = JSON.stringify(queryData); const encodedData = textEncoder.encode(dataString); - console.log("lbh: queryData",queryData); + console.log("lbh: queryData", queryData); WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_CMD, encodedData); } this.functionListener!(it, this.clickFuncVaddrList); -- Gitee From abda020488b886db24cdf725a59659d7f77108c4 Mon Sep 17 00:00:00 2001 From: luobinghao Date: Fri, 13 Dec 2024 15:37:09 +0800 Subject: [PATCH 10/13] delete wrong register callback and add timeout limit Signed-off-by: luobinghao --- .../trace/sheet/hiperf/TabPerfFuncAsm.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index c8ff2d33e..4f30b35f2 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -91,16 +91,6 @@ export class TabPerfFuncAsm extends BaseElement { } } }) as EventListener); - // 注册汇编代码请求回调函数 - WebSocketManager.getInstance()?.registerCallback(TypeConstants.DISASSEMBLY_TYPE, this.receiveAsmData.bind(this)); - } - - private receiveAsmData(cmd: unknown, e: unknown): void { - // @ts-ignore - const result = JSON.parse(new TextDecoder().decode(e)); - if (result.resultCode === 0) { - this.currentAsmList = JSON.parse(result.resultMessage); - } } private updateTitle(): void { @@ -189,11 +179,8 @@ export class TabPerfFuncAsm extends BaseElement { new Promise((_, reject) => setTimeout(() => { WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); reject(new Error('Request timeout')); - }, 5000)) + }, 20000)) ]); - - // 5. 更新表格 - } catch (error) { console.error('Error:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error'; -- Gitee From 31d18090428fa7832c60450b95771fd40c5e0ea1 Mon Sep 17 00:00:00 2001 From: z30061262 Date: Sun, 29 Dec 2024 20:46:18 +0800 Subject: [PATCH 11/13] =?UTF-8?q?so=E6=B1=87=E7=BC=96=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E8=A1=8C=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhuheng --- ide/src/trace/bean/PerfAnalysis.ts | 10 +- .../trace/component/trace/base/TraceSheet.ts | 47 ++++---- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 1 - .../trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 10 +- .../trace/sheet/hiperf/TabPerfFuncAsm.ts | 111 +++++++++++------- .../logic-worker/ProcedureLogicWorkerPerf.ts | 5 +- ide/src/webSocket/Constants.ts | 2 +- ide/src/webSocket/WebSocketManager.ts | 43 ++++--- 8 files changed, 130 insertions(+), 99 deletions(-) diff --git a/ide/src/trace/bean/PerfAnalysis.ts b/ide/src/trace/bean/PerfAnalysis.ts index abe0cf25d..5e2bfd211 100644 --- a/ide/src/trace/bean/PerfAnalysis.ts +++ b/ide/src/trace/bean/PerfAnalysis.ts @@ -20,15 +20,17 @@ export class PerfFunctionAsmParam { } export class FormattedAsmInstruction { - selfcount:number = 0; - percent:number = 0; + selfcount: number = 0; + percent: number = 0; addr: number = 0; instruction: string = ''; + sourceLine: string = ''; } export class OriginAsmInstruction { - addr:string = ''; - instruction:string = ''; + addr: string = ''; + instruction: string = ''; + sourceLine: string = ''; } export class PerfFunctionAsmShowUpData { diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts index 15aaa2a3c..9ba7d1133 100644 --- a/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -95,6 +95,7 @@ import { PerfToolStruct } from '../../../database/ui-worker/ProcedureWorkerPerfT import { GpuCounterStruct } from '../../../database/ui-worker/ProcedureWorkerGpuCounter'; import { TabPaneGpuCounter } from '../sheet/gpu-counter/TabPaneGpuCounter'; import { TabPaneSliceChild } from '../sheet/process/TabPaneSliceChild'; +import { TabPerfFuncAsm } from '../sheet/hiperf/TabPerfFuncAsm'; import { XpowerStatisticStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerStatistic'; import { XpowerAppDetailStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerAppDetail'; import { XpowerWifiStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerWifi'; @@ -103,11 +104,11 @@ import { XpowerThreadInfoStruct } from '../../../database/ui-worker/ProcedureWor import { TabPaneXpowerThreadInfoSelection } from '../sheet/xpower/TabPaneXpowerThreadInfoSelection'; import { TabPaneXpowerGpuFreqSelection } from '../sheet/xpower/TabPaneXpowerGpuFreqSelection'; import { XpowerGpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerGpuFreq'; -import {WebSocketManager} from "../../../../webSocket/WebSocketManager"; -import {Constants, TypeConstants} from "../../../../webSocket/Constants"; -import {SpStatisticsHttpUtil} from "../../../../statistics/util/SpStatisticsHttpUtil"; +import { WebSocketManager} from "../../../../webSocket/WebSocketManager"; +import { Constants, TypeConstants} from "../../../../webSocket/Constants"; import { PerfFunctionAsmParam } from '../../../bean/PerfAnalysis'; -import { TabPerfFuncAsm } from '../sheet/hiperf/TabPerfFuncAsm'; +import { info,error } from '../../../../log/Log'; + @element('trace-sheet') export class TraceSheet extends BaseElement { @@ -132,9 +133,7 @@ export class TraceSheet extends BaseElement { private optionsDiv: LitPopover | undefined | null; private optionsSettingTree: LitTree | undefined | null; private tabPaneHeight: string = ''; - private enc = new TextEncoder(); - private dec = new TextDecoder(); - private REQ_BUF_SIZE = 4 * 1024 * 1024; + private REQ_BUF_SIZE = 1024 * 1024; static get observedAttributes(): string[] { return ['mode']; @@ -314,21 +313,19 @@ export class TraceSheet extends BaseElement { (it): boolean => it.id !== this.currentPaneID ? (it.hidden = true) : (it.hidden = false) ); - let pane = this.getPaneByID("tab-perf-func-asm"); //通过Id找到需要展示的Tab页 - pane.closeable = true; - pane.hidden = false; + let asmPane = this.getPaneByID("tab-perf-func-asm"); //通过Id找到需要展示的Tab页 + asmPane.closeable = true; + asmPane.hidden = false; // @ts-ignore - pane.tab = evt.tableName; //设置Tab页标题 - console.log("lbh: evt", evt); - console.log("lbh: vaadrlist", vaddrList); + asmPane.tab = evt.tableName; //设置Tab页标题 let param = new PerfFunctionAsmParam(); param.vaddrList = vaddrList; // @ts-ignore param.functionName = evt.tableName; // @ts-ignore param.totalCount = evt.count; - (pane.children.item(0) as TabPerfFuncAsm)!.data = param; - this.litTabs!.activeByKey(pane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 + (asmPane.children.item(0) as TabPerfFuncAsm)!.data = param; + this.litTabs!.activeByKey(asmPane.key); //显示key值(sheetconfig里面对应的index是一个数字)对应的Tab页 } private nativeAnalysisListener(e: MouseEvent): void { @@ -621,7 +618,9 @@ export class TraceSheet extends BaseElement { private async uploadSoOrAN(fileList: Array): Promise { if (fileList) { - fileList.sort((a, b) => b.size - a.size); + fileList.sort((a, b) => { + return b.size - a.size; + }); await this.uploadAllFiles(fileList); } } @@ -636,12 +635,12 @@ export class TraceSheet extends BaseElement { const file = filesToUpload[i]; try { await this.uploadSingleFile(file); - console.log('File ${file.name} uploaded successfully.'); - } catch (error) { - console.error('Failed to upload file: ${file.name}, error'); + info(`File ${file.name} uploaded successfully.`); + } catch (err) { + error(`Failed to upload file: ${file.name}, error: `, err); } } - console.log("All files have been uploaded."); + info(`All files have been uploaded.`); } @@ -668,16 +667,15 @@ export class TraceSheet extends BaseElement { let jsonRes = JSON.parse(jsonString); if (cmd === Constants.DISASSEMBLY_SAVE_BACK_CMD) { if (jsonRes.fileName === fileName && jsonRes.bufferIndex === bufferIndex) { - wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived) + wsInstance!.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, onAckReceived); clearTimeout(timeout); - if (jsonRes.resultCode == 0) { - console.log('ACK received for file: ${jsonRes.fileName}, index: ${jsonRes.bufferIndex}'); + if (jsonRes.resultCode === 0) { bufferIndex++; // 当收到对应分片的 ACK 时,resolve Promise,继续上传下一个分片 resolve(); }else{ // 上传失败,拒绝 Promise 并返回 - reject(new Error('Upload failed for file: ${fileName}, index: ${jsonRes.bufferIndex})')); + reject(new Error(`Upload failed for file: ${fileName}, index: ${jsonRes.bufferIndex})`)); } } } @@ -712,7 +710,6 @@ export class TraceSheet extends BaseElement { buffer = null; blob = null; } - console.log('Upload complete for file: ${fileName}'); } }; diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 09d10177c..7bfaef4fc 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -593,7 +593,6 @@ export class TabPanePerfAnalysis extends BaseElement { }; const dataString = JSON.stringify(queryData); const encodedData = textEncoder.encode(dataString); - console.log("lbh: queryData", queryData); WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_CMD, encodedData); } this.functionListener!(it, this.clickFuncVaddrList); diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts index f3c2b86ea..67032fbe2 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -53,14 +53,16 @@ export const TabPerfFuncAsmHtml = `
Function Name:
Total Count:
+
.text Section File Off:
- - - - + + + + +
diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index 4f30b35f2..0d4d528ac 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -1,3 +1,17 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF unknown KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import { TabPerfFuncAsmHtml } from "./TabPerfFuncAsm.html"; import { BaseElement, element } from "../../../../../base-ui/BaseElement"; import { LitTable } from "../../../../../base-ui/table/lit-table"; @@ -17,29 +31,35 @@ export class TabPerfFuncAsm extends BaseElement { private totalCount: number = 0; private functionNameElement: HTMLDivElement | null | undefined; private totalCountElement: HTMLDivElement | null | undefined; + private textFileOffElement: HTMLDivElement | null | undefined; private errorMessageElement: HTMLDivElement | null | undefined; private funcBaseAddr: bigint = BigInt(0); // Key: offset; Value: selfcount private funcSampleMap: Map = new Map(); private showUpData: FormattedAsmInstruction[] = []; private originalShowUpData: FormattedAsmInstruction[] = []; - private currentAsmList: Array = []; private formattedAsmIntructionArray: FormattedAsmInstruction[] = []; + private resizeObserver: ResizeObserver | null = null; + initHtml(): string { return TabPerfFuncAsmHtml; } initElements(): void { this.assmblerTable = this.shadowRoot!.querySelector( - "#perf-function-asm-table" + "#perf-function-asm-table" ); this.loadingElement = - this.shadowRoot!.querySelector("#loading"); + this.shadowRoot!.querySelector("#loading"); this.functionNameElement = - this.shadowRoot!.querySelector("#function-name"); + this.shadowRoot!.querySelector("#function-name"); this.totalCountElement = - this.shadowRoot!.querySelector("#total-count"); + this.shadowRoot!.querySelector("#total-count"); + this.textFileOffElement = + this.shadowRoot!.querySelector("#text-file-off"); + this.textFileOffElement!.style.display = 'none'; this.errorMessageElement = this.shadowRoot!.querySelector("#error-message"); + this.assmblerTable!.style.display = "grid"; this.assmblerTable!.itemTextHandleMap.set("addr", (value: unknown) => { @@ -58,26 +78,25 @@ export class TabPerfFuncAsm extends BaseElement { return (value as string) === "" ? "INVALID" : (value as string); }); + this.assmblerTable!.itemTextHandleMap.set("sourceLine", (value: unknown) => { + return (value as string) || ""; + }); + this.assmblerTable!.addEventListener("column-click", ((evt: Event) => { - const { key, sort } = (evt as CustomEvent).detail; - console.log("lbh:sort", sort) + const {key, sort} = (evt as CustomEvent).detail; if (key === "selfcount") { if (sort === 0) { - console.log("lbh: sort0") this.assmblerTable!.recycleDataSource = this.originalShowUpData; - console.log("lbh:sort recycle", this.assmblerTable!.recycleDataSource) - console.log("lbh:sort originalShowUpData", this.originalShowUpData) this.assmblerTable!.reMeauseHeight(); } else { this.showUpData.sort((a, b) => { return sort === 1 - ? a.selfcount - b.selfcount - : b.selfcount - a.selfcount; + ? a.selfcount - b.selfcount + : b.selfcount - a.selfcount; }); this.assmblerTable!.recycleDataSource = this.showUpData; this.assmblerTable!.reMeauseHeight(); } - console.log("after sort: ", this.originalShowUpData) } else if (key === "percent") { if (sort === 0) { this.assmblerTable!.recycleDataSource = this.originalShowUpData; @@ -98,7 +117,6 @@ export class TabPerfFuncAsm extends BaseElement { this.functionNameElement!.innerHTML = `Function Name: ${this.functionName}`; this.totalCountElement!.innerHTML = `Total Count: ${this.totalCount}`; } - console.log(this.totalCount) } private showLoading(): void { @@ -127,7 +145,7 @@ export class TabPerfFuncAsm extends BaseElement { } set data(data: PerfFunctionAsmParam) { - if (this.functionName === data.functionName) { + if (this.functionName === data.functionName || data.functionName === undefined) { return; } @@ -153,43 +171,43 @@ export class TabPerfFuncAsm extends BaseElement { new Promise((resolve, reject) => { callback = (cmd: number, e: Uint8Array) => { try { - console.log('Received cmd:', cmd, 'Expected:', Constants.DISASSEMBLY_QUERY_BACK_CMD); - + if (cmd === Constants.DISASSEMBLY_QUERY_BACK_CMD) { const result = JSON.parse(new TextDecoder().decode(e)); if (result.resultCode === 0) { + if (result.anFileOff) { + this.textFileOffElement!.innerHTML = `.text Section File Off ${result.anFileOff}`; + this.textFileOffElement!.style.display = 'block'; + } else { + this.textFileOffElement!.style.display = 'none'; + } this.formatAsmInstruction(JSON.parse(result.resultMessage)); this.calcutelateShowUpData(); resolve(); } else { - reject(new Error(`Failed with code: ${result.resultCode}`)); + reject(new Error(`Failed with code: ${result.resultCode}, error message: ${result.resultMessage}`)); } - } else { - reject(new Error(`Unexpected command: ${cmd}`)); + WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); } - WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); - reject(error); + reject(new Error(`Error while processing WebSocket message: ${errorMessage}`)); } }; - + WebSocketManager.getInstance()?.registerCallback(TypeConstants.DISASSEMBLY_TYPE, callback); }), new Promise((_, reject) => setTimeout(() => { WebSocketManager.getInstance()?.unregisterCallback(TypeConstants.DISASSEMBLY_TYPE, callback); - reject(new Error('Request timeout')); - }, 20000)) + reject(new Error('Request timeout, please install the extended service according to the help document')); + }, 30000)) ]); } catch (error) { - console.error('Error:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error'; - this.showError(`Error: can't get assembly code because ${errorMessage},show sample list without assembly code`); + this.showError(`Error: can't get assembly instruction because ${errorMessage}, show sample list without assembly instruction`); this.calcutelateErrorShowUpData(); } finally { - console.log("lbh:finally:originalShowUpData ", this.originalShowUpData) - console.log("lbh:finally:funcBaseAddr ", this.funcBaseAddr) - console.log("lbh:finally:funcSampleMap ", this.funcSampleMap) this.showUpData = [...this.originalShowUpData]; this.assmblerTable!.recycleDataSource = this.showUpData; this.assmblerTable!.reMeauseHeight(); @@ -205,12 +223,10 @@ export class TabPerfFuncAsm extends BaseElement { percent: Math.round((selfCount / this.totalCount) * 10000) / 100, // 地址计算也使用 BigInt addr: Number(BigInt.asUintN(64, this.funcBaseAddr + BigInt(offsetToVaddr))), - instruction: '' + instruction: '', + sourceLine: '' }) }) - console.log("lbh:calcutelateErrorShowUpData originalShowUpData ", this.originalShowUpData) - console.log("lbh:calcutelateErrorShowUpData funcBaseAddr ", this.funcBaseAddr) - console.log("lbh:calcutelateErrorShowUpData funcSampleMap ", this.funcSampleMap) } private calculateFuncAsmSapleCount(vaddrList: Array): void { @@ -228,6 +244,7 @@ export class TabPerfFuncAsm extends BaseElement { percent: 0, addr: parseInt(instructs.addr, 16), instruction: instructs.instruction, + sourceLine: instructs.sourceLine }) as FormattedAsmInstruction); } @@ -237,7 +254,6 @@ export class TabPerfFuncAsm extends BaseElement { this.funcSampleMap.clear(); this.showUpData = []; this.originalShowUpData = []; - this.currentAsmList = []; this.formattedAsmIntructionArray = []; this.assmblerTable!.recycleDataSource = []; } @@ -252,13 +268,24 @@ export class TabPerfFuncAsm extends BaseElement { } public connectedCallback(): void { - new ResizeObserver(() => { + super.connectedCallback(); + // 初始化 ResizeObserver + this.resizeObserver = new ResizeObserver(() => { if (this.assmblerTable && this.parentElement) { - this.assmblerTable.style.height = `${ - this.parentElement.clientHeight - 50 - }px`; - this.assmblerTable.reMeauseHeight(); + this.assmblerTable.style.height = `${this.parentElement.clientHeight - 50}px`; + this.assmblerTable!.reMeauseHeight(); } - }).observe(this.parentElement!); + }); + this.resizeObserver.observe(this.parentElement!); + } + + public disconnectedCallback(): void { + super.disconnectedCallback(); + + // 断开 ResizeObserver + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + this.resizeObserver = null; + } } -} +} \ No newline at end of file diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 21438ebf7..2f63034e2 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -358,7 +358,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { private perfGetVaddr(data: unknown) { // @ts-ignore const params = data.params; - this.backVaddrData(data) + this.backVaddrData(data); } backVaddrData(data: unknown) { @@ -1270,9 +1270,6 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { break; case 'getCurrentDataFromDbBottomUp': this.queryDataFromDb(funcArgs, 'perf-bottomUp'); - case 'getCurrentDataFromDb': - this.queryDataFromDb(funcArgs); - break; case 'getVaddrToFile': this.queryVaddrToFile(funcArgs); break; diff --git a/ide/src/webSocket/Constants.ts b/ide/src/webSocket/Constants.ts index b1b752750..c44949c08 100644 --- a/ide/src/webSocket/Constants.ts +++ b/ide/src/webSocket/Constants.ts @@ -36,6 +36,7 @@ export class TypeConstants { static DIAGNOSIS_TYPE = 8; static SENDDB_CMD = 1; static DIAGNOSIS_CMD = 3; + static DISASSEMBLY_TYPE = 12; static ARKTS_TYPE = 9; static PROCESS_TYPE = 3; static USB_TYPE = 10; @@ -45,5 +46,4 @@ export class TypeConstants { static USB_GET_EVENT = 4; static USB_GET_APP = 5; static USB_GET_VERSION = 6; - static DISASSEMBLY_TYPE = 10; } \ No newline at end of file diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index a9d22d20e..c01c5a4fe 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -213,20 +213,32 @@ export class WebSocketManager { * 模块调用 */ registerMessageListener(type: number, callback: Function, eventCallBack: Function): void { - if (!this.distributeMap.has(type)) { - this.distributeMap.set(type, { 'messageCallbacks': [], 'eventCallBack': eventCallBack }); - } - const callbackObj = this.distributeMap.get(type)!; - callbackObj.messageCallbacks.push(callback); + this.register(type, callback, eventCallBack); } - // 注册回调函数 + /** + * 消息监听器 + * listener是不同模块传来接收数据的函数 + * 模块调用 + */ registerCallback(type: number, callback: Function): void { - if (!this.distributeMap.has(type)) { - this.distributeMap.set(type, { 'messageCallbacks': [], 'eventCallBack': () => {} }); + this.register(type, callback); + } + + private register(type: number, callback: Function, eventCallBack: Function = () => {}): void { + let callbackObj = this.distributeMap.get(type); + if (!callbackObj) { + callbackObj = { + messageCallbacks: [callback], + eventCallBack: eventCallBack + }; + this.distributeMap.set(type, callbackObj); + } else { + if (!callbackObj.messageCallbacks.includes(callback)) { + callbackObj.messageCallbacks.push(callback); + } + callbackObj.eventCallBack = eventCallBack; } - const callbackObj = this.distributeMap.get(type)!; - callbackObj.messageCallbacks.push(callback); } // 删除回调函数 @@ -234,10 +246,7 @@ export class WebSocketManager { if (!this.distributeMap.has(type)) { return; } - // 获取指定类型的回调对象 const callbackObj = this.distributeMap.get(type)!; - - // 在回调数组中查找并移除与传入的回调函数匹配的项 callbackObj.messageCallbacks = callbackObj.messageCallbacks.filter((cb) => cb !== callback); // 如果回调数组为空,同时 eventCallBack 也为空,则可以删除整个类型 @@ -276,7 +285,7 @@ export class WebSocketManager { this.websocket!.send(encode!); } - // 定时检查心跳 + // 定时检查心跳 sendHeartbeat(): void { this.heartbeatInterval = window.setInterval(() => { if (this.status === GetStatuses.READY) { @@ -316,7 +325,7 @@ export class WebSocketManager { } // 检查状态 中间状态,最终失败状态,最终成功状态 - checkStatus(type: number): void { // 更改参数名称为 type,以反映实际传递的值 + checkStatus(type: number): void { // @ts-ignore let statuses = this.getStatusesPrompt()[this.status]; const distributeEntry = this.distributeMap.get(type); @@ -325,11 +334,9 @@ export class WebSocketManager { if (statuses.type === INTERMEDIATE_STATE) { distributeEntry.eventCallBack(this.status); } else if (statuses.type === FAILED_STATE) { - this.reconnect = type; // 确认这是您想要的逻辑 + this.reconnect = type; this.connectWebSocket(); } - } else { - console.error('No valid eventCallBack found for type: ${type}'); } } -- Gitee From 9d8d02af45e87b0d21098cfbf8d4682c2143f0cb Mon Sep 17 00:00:00 2001 From: luobinghao Date: Fri, 17 Jan 2025 15:44:06 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B8=83=E5=B1=80=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0.text=20section=E6=98=BE=E7=A4=BA,=E5=88=A0?= =?UTF-8?q?=E9=99=A4functionName=EF=BC=8Ctoatl=20count=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=88=B0=E5=8F=B3=E8=BE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: luobinghao --- .../trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 11 +++++++++-- .../component/trace/sheet/hiperf/TabPerfFuncAsm.ts | 11 +++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts index 67032fbe2..c0883b93a 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -36,6 +36,11 @@ export const TabPerfFuncAsmHtml = ` .title-label { font-weight: bold; } +.title-row { + display: flex; + justify-content: space-between; + align-items: center; +} .loading { position: absolute; top: 50%; @@ -51,8 +56,10 @@ export const TabPerfFuncAsmHtml = `
-
Function Name:
-
Total Count:
+
+
.text section:
+
Total Count:
+
.text Section File Off:
diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index 0d4d528ac..69e30cb49 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -29,7 +29,6 @@ export class TabPerfFuncAsm extends BaseElement { private loadingElement: HTMLElement | null | undefined; private functionName: string = ""; private totalCount: number = 0; - private functionNameElement: HTMLDivElement | null | undefined; private totalCountElement: HTMLDivElement | null | undefined; private textFileOffElement: HTMLDivElement | null | undefined; private errorMessageElement: HTMLDivElement | null | undefined; @@ -51,13 +50,10 @@ export class TabPerfFuncAsm extends BaseElement { ); this.loadingElement = this.shadowRoot!.querySelector("#loading"); - this.functionNameElement = - this.shadowRoot!.querySelector("#function-name"); this.totalCountElement = this.shadowRoot!.querySelector("#total-count"); this.textFileOffElement = this.shadowRoot!.querySelector("#text-file-off"); - this.textFileOffElement!.style.display = 'none'; this.errorMessageElement = this.shadowRoot!.querySelector("#error-message"); this.assmblerTable!.style.display = "grid"; @@ -112,9 +108,8 @@ export class TabPerfFuncAsm extends BaseElement { }) as EventListener); } - private updateTitle(): void { + private updateTotalCount(): void { if (this.functionName) { - this.functionNameElement!.innerHTML = `Function Name: ${this.functionName}`; this.totalCountElement!.innerHTML = `Total Count: ${this.totalCount}`; } } @@ -154,7 +149,7 @@ export class TabPerfFuncAsm extends BaseElement { this.clearData(); this.functionName = data.functionName; this.totalCount = data.totalCount; - this.updateTitle(); + this.updateTotalCount(); this.showLoading(); // @ts-ignore const vaddrInFile = data.vaddrList[0].vaddrInFile; @@ -176,7 +171,7 @@ export class TabPerfFuncAsm extends BaseElement { const result = JSON.parse(new TextDecoder().decode(e)); if (result.resultCode === 0) { if (result.anFileOff) { - this.textFileOffElement!.innerHTML = `.text Section File Off ${result.anFileOff}`; + this.textFileOffElement!.innerHTML = `.text section: ${result.anFileOff}`; this.textFileOffElement!.style.display = 'block'; } else { this.textFileOffElement!.style.display = 'none'; -- Gitee From 2fc8aaa49ee9ec9ca9696f0270b0b86f9160802f Mon Sep 17 00:00:00 2001 From: luobinghao Date: Mon, 20 Jan 2025 11:28:54 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E4=B8=AA.text?= =?UTF-8?q?=20section=EF=BC=8C=E4=BF=AE=E5=A4=8D.text=20section=20?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E6=97=B6=20total=20count=20?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=9C=A8=E5=B7=A6=E8=BE=B9=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: luobinghao --- .../component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts index c0883b93a..70f116e9a 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -40,6 +40,14 @@ export const TabPerfFuncAsmHtml = ` display: flex; justify-content: space-between; align-items: center; + width: 100%; +} +#text-file-off { + flex-grow: 0; +} +#total-count { + flex-grow: 1; + text-align: right; } .loading { position: absolute; @@ -60,7 +68,6 @@ export const TabPerfFuncAsmHtml = `
.text section:
Total Count:
-
.text Section File Off:
-- Gitee