From 725d11069298c5442b3cba4e7220c1d00c91b009 Mon Sep 17 00:00:00 2001 From: zhangzhuozhou Date: Thu, 24 Apr 2025 14:59:59 +0800 Subject: [PATCH 01/51] =?UTF-8?q?feat:=E9=80=82=E9=85=8Dtrace=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E5=90=8D=E6=97=A0=E6=B3=95=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhuozhou --- trace_streamer/src/filter/process_filter.cpp | 19 +++++++++++++++++++ trace_streamer/src/filter/process_filter.h | 1 + .../rawtrace_parser/ftrace_processor.cpp | 14 ++++++++++++-- .../parser/rawtrace_parser/ftrace_processor.h | 1 + .../rawtrace_parser/rawtrace_parser.cpp | 2 ++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/trace_streamer/src/filter/process_filter.cpp b/trace_streamer/src/filter/process_filter.cpp index e05a60f8..199b4705 100644 --- a/trace_streamer/src/filter/process_filter.cpp +++ b/trace_streamer/src/filter/process_filter.cpp @@ -244,6 +244,25 @@ std::tuple ProcessFilter::CreateProcessMaybe( return std::make_tuple(internalPid, process); } +void ProcessFilter::UpdateProcessNameByNameToTid(std::unordered_map &tidToName) +{ + auto processList = traceDataCache_->GetConstProcessData(); + auto size = processList.size(); + for (auto row = 0; row < size; row++) { + if (!processList[row].cmdLine_.empty()) { + continue; + } + auto process = traceDataCache_->GetProcessData(row); + if (!process) { + continue; + } + auto it = tidToName.find(process->pid_); + if (it != tidToName.end()) { + auto res = UpdateOrCreateProcessWithName(process->pid_, it->second.c_str()); + TS_LOGI("Update process name %s to tid %d", it->second.c_str(), process->pid_); + } + } +} void ProcessFilter::Clear() { tidMappingSet_.clear(); diff --git a/trace_streamer/src/filter/process_filter.h b/trace_streamer/src/filter/process_filter.h index 1ef82fe9..95851350 100644 --- a/trace_streamer/src/filter/process_filter.h +++ b/trace_streamer/src/filter/process_filter.h @@ -44,6 +44,7 @@ public: void AddCpuStateCount(uint32_t itid); void AddProcessSliceNum(uint32_t ipid); void Clear(); + void UpdateProcessNameByNameToTid(std::unordered_map &tidToName); private: std::tuple CreateProcessMaybe(uint32_t pid, uint64_t startT); diff --git a/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.cpp b/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.cpp index 8e70920a..d77ee53f 100644 --- a/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.cpp +++ b/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.cpp @@ -175,7 +175,10 @@ static std::string GetName(const std::map &nameMap, int type) static std::string GetFieldTypeName(EventFieldType type) { static std::map toNames = { -#define VALUE_NAME(x) {x, #x} +#define VALUE_NAME(x) \ + { \ + x, #x \ + } VALUE_NAME(FIELD_TYPE_INVALID), VALUE_NAME(FIELD_TYPE_BOOL), VALUE_NAME(FIELD_TYPE_INT8), VALUE_NAME(FIELD_TYPE_UINT8), VALUE_NAME(FIELD_TYPE_INT16), VALUE_NAME(FIELD_TYPE_UINT16), VALUE_NAME(FIELD_TYPE_INT32), VALUE_NAME(FIELD_TYPE_UINT32), VALUE_NAME(FIELD_TYPE_INT64), @@ -192,7 +195,10 @@ static std::string GetFieldTypeName(EventFieldType type) static std::string GetProtoTypeName(ProtoFieldType type) { static std::map toNames = { -#define VALUE_NAME(x) {x, #x} +#define VALUE_NAME(x) \ + { \ + x, #x \ + } VALUE_NAME(PROTO_TYPE_UNKNOWN), VALUE_NAME(PROTO_TYPE_DOUBLE), VALUE_NAME(PROTO_TYPE_FLOAT), VALUE_NAME(PROTO_TYPE_INT64), VALUE_NAME(PROTO_TYPE_UINT64), VALUE_NAME(PROTO_TYPE_INT32), VALUE_NAME(PROTO_TYPE_FIXED64), VALUE_NAME(PROTO_TYPE_FIXED32), VALUE_NAME(PROTO_TYPE_BOOL), @@ -763,5 +769,9 @@ bool FtraceProcessor::HandleFtraceEvent(FtraceEvent &ftraceEvent, FtraceEventProcessor::GetInstance().HandleEvent(ftraceEvent, data, dataSize, format); return true; } +std::unordered_map &FtraceProcessor::GetTidToName() +{ + return taskNameDict_; +} } // namespace TraceStreamer } // namespace SysTuning diff --git a/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.h b/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.h index f5d05999..d8e8a025 100644 --- a/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.h +++ b/trace_streamer/src/parser/rawtrace_parser/ftrace_processor.h @@ -86,6 +86,7 @@ public: bool HandleFtraceEvent(FtraceEvent &ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat &format); bool HandleFtraceCommonFields(FtraceEvent &ftraceEvent, uint8_t data[], size_t dataSize, const EventFormat &format); + std::unordered_map &GetTidToName(); private: std::regex fixedCharArrayRegex_; diff --git a/trace_streamer/src/parser/rawtrace_parser/rawtrace_parser.cpp b/trace_streamer/src/parser/rawtrace_parser/rawtrace_parser.cpp index bc7e3cf0..909d2c4e 100644 --- a/trace_streamer/src/parser/rawtrace_parser/rawtrace_parser.cpp +++ b/trace_streamer/src/parser/rawtrace_parser/rawtrace_parser.cpp @@ -41,6 +41,8 @@ void RawTraceParser::WaitForParserEnd() restCommDataCnt_ = 0; hasGotHeader_ = false; curCpuCoreNum_ = 0; + auto tidToName = ftraceProcessor_->GetTidToName(); + streamFilters_->processFilter_->UpdateProcessNameByNameToTid(tidToName); ClearRawTraceData(); TS_LOGI("Parser raw trace end!"); } -- Gitee From a5348a6c163be82f188afe4c42282848696a5b72 Mon Sep 17 00:00:00 2001 From: zhangzepeng Date: Thu, 24 Apr 2025 15:24:19 +0800 Subject: [PATCH 02/51] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzepeng --- ide/src/trace/database/TraceWorker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ide/src/trace/database/TraceWorker.ts b/ide/src/trace/database/TraceWorker.ts index 1923ed8a..9a7726db 100644 --- a/ide/src/trace/database/TraceWorker.ts +++ b/ide/src/trace/database/TraceWorker.ts @@ -313,6 +313,7 @@ function initModuleCallBackAndFun(): void { let tlvResultCallback = (heapPtr: number, size: number, type: number, isEnd: number): void => { //@ts-ignore let out: Uint8Array = wasmModule.HEAPU8.slice(heapPtr, heapPtr + size); + //@ts-ignore protoDataMap.set(type, BatchSphData.decode(out).values); }; //@ts-ignore -- Gitee From 14798d02b2d7756c041e3367f45e0d7153924d27 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 25 Apr 2025 11:41:08 +0800 Subject: [PATCH 03/51] =?UTF-8?q?feat:1=E3=80=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=9C=8D=E5=8A=A1=E6=8A=93=E5=8F=96longtrace?= =?UTF-8?q?=202=E3=80=81=E6=8A=93=E5=8F=96longtrace=E4=B8=8D=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=BF=AB=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- ide/src/trace/component/SpRecordTrace.ts | 82 +++++++++++++++++++ .../component/setting/SpRecordSetting.ts | 2 + 2 files changed, 84 insertions(+) diff --git a/ide/src/trace/component/SpRecordTrace.ts b/ide/src/trace/component/SpRecordTrace.ts index dfb8d1b8..457e57ca 100644 --- a/ide/src/trace/component/SpRecordTrace.ts +++ b/ide/src/trace/component/SpRecordTrace.ts @@ -118,6 +118,10 @@ export class SpRecordTrace extends BaseElement { private stop = 'StopRecord'; private nowChildItem: HTMLElement | undefined; private longTraceList: Array = []; + private fileList: Array<{ + fileName: string, + file: File + }> = []; private refreshDeviceTimer: number | undefined; private hintEl: HTMLSpanElement | undefined; private selectedTemplate: Map = new Map(); @@ -532,6 +536,7 @@ export class SpRecordTrace extends BaseElement { let isCheckSnapshot = this.spArkTs!.radioBoxType === 0 ? true : false; // 是否check snapshot let isCheckTimeLine = this.spArkTs!.radioBoxType === 1 ? true : false; // 是否 check timeline + let isLongTrace = SpApplication.isLongTrace; let maxDur = this.recordSetting!.maxDur; // 抓取trace的时长 let snapShotDur = this.recordSetting!.snapShot;//截图 SpRecordTrace.snapShotDuration = snapShotDur; @@ -542,6 +547,7 @@ export class SpRecordTrace extends BaseElement { let enableCpuProfiler = this.spArkTs!.isStartCpuProfiler; let params: unknown = { + isLongTrace: isLongTrace, isRecordArkTs: isRecordArkTs, isRecordHitrace: isRecordHitrace, type: '', @@ -613,12 +619,88 @@ export class SpRecordTrace extends BaseElement { this.litSearch!.setPercent('Tracing htrace down', -1); } else if (cmd === 8) { this.litSearch!.setPercent('Downloading Hitrace file...', -1); + } else if (cmd === 9) {// @ts-ignore + let re = JSON.parse(new TextDecoder('utf-8').decode(result)); + let binaryString = window.atob(re.data); + let len = binaryString.length; + let bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + re.data = bytes.buffer; + let fileInfo = { + fileName: re.fileName, + file: new File([re.data], re.fileName) + }; + this.fileList.push(fileInfo); + this.longTraceList.push(fileInfo.fileName); + if (this.fileList.length === re.total) { + this.openLongTraceHandle(); + } } }; WebSocketManager.getInstance()!.registerMessageListener(TypeConstants.ARKTS_TYPE, onmessageCallBack, this.eventCallBack); WebSocketManager.getInstance()!.sendMessage(TypeConstants.ARKTS_TYPE, 1, encoder.encode(JSON.stringify(params))); }; + async openLongTraceHandle() { + this.fileList.sort((a, b) => { + const getNumber = (name: string) => { + const match = name.match(/_(\d+)\.htrace$/); + return match ? parseInt(match[1]) : 0; + }; + return getNumber(a.fileName) - getNumber(b.fileName); + }); + let timStamp = new Date().getTime(); + this.sp!.longTraceHeadMessageList = []; + for (const fileInfo of this.fileList) { + await this.saveLongTrace(fileInfo.file, timStamp); + } + await this.openLongTrace(timStamp); + this.fileList = []; + this.longTraceList = []; + } + + async saveLongTrace(file: File, timStamp: number) { + let traceTypePage = this.getLongTraceTypePage(); + let types = this.sp!.fileTypeList.filter(type => + file.name.toLowerCase().includes(type.toLowerCase()) + ); + let pageNumber = 0; + let fileType = types[0] || 'trace'; + if (types.length === 0) { + let searchNumber = Number( + file.name.substring( + file.name.lastIndexOf('_') + 1, + file.name.lastIndexOf('.') + ) + ) - 1; + pageNumber = traceTypePage.lastIndexOf(searchNumber); + } + this.litSearch!.setPercent(`downloading ${fileType} file`, 101); + await this.saveIndexDBByLongTrace(file, fileType, pageNumber, timStamp); + } + + async openLongTrace(timStamp: number) { + let main = this.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; + let children = main.menus as Array; + let child = children[1].children as Array; + let fileHandler = child[0].clickHandler; + if (fileHandler && !SpRecordTrace.cancelRecord) { + this.freshConfigMenuDisable(false); + this.freshMenuDisable(false); + this.buttonDisable(false); + this.recordButtonDisable(false); + fileHandler({ + detail: { + timeStamp: timStamp + } + }, true); + } else { + SpRecordTrace.cancelRecord = false; + } + } + recordTempAddProbe = (ev: CustomEventInit<{ elementId: string }>): void => { if ( FlagsConfig.DEFAULT_CONFIG.find((flagItem) => { diff --git a/ide/src/trace/component/setting/SpRecordSetting.ts b/ide/src/trace/component/setting/SpRecordSetting.ts index 6973ae7a..6ed9c65f 100644 --- a/ide/src/trace/component/setting/SpRecordSetting.ts +++ b/ide/src/trace/component/setting/SpRecordSetting.ts @@ -244,12 +244,14 @@ export class SpRecordSetting extends BaseElement { rootEl.removeChild(longTraceMaxSlide); } this.outputPath!.value = 'hiprofiler_data.htrace'; + this.snapShotNumber!.style.display = 'grid'; } private longTraceModelRadioHandler(rootEl: HTMLDivElement, longTraceMaxSlide: HTMLDivElement): void { SpApplication.isLongTrace = true; rootEl.appendChild(longTraceMaxSlide); this.outputPath!.value = 'long_trace'; + this.snapShotNumber!.style.display = 'none'; } private maxSizeInputHandler(maxSizeSliders: LitSlider, maxSizeParentElement: Element): void { -- Gitee From 65ddfa23fe85ee1cedc05be35bc8a2dc4d8a5096 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Sun, 27 Apr 2025 16:40:48 +0800 Subject: [PATCH 04/51] =?UTF-8?q?fix:=E6=89=A9=E5=B1=95=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/doc/quickstart_extensions.html | 2 +- ide/src/webSocket/WebSocketManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ide/src/doc/quickstart_extensions.html b/ide/src/doc/quickstart_extensions.html index fab0d847..d75add92 100644 --- a/ide/src/doc/quickstart_extensions.html +++ b/ide/src/doc/quickstart_extensions.html @@ -811,7 +811,7 @@ 在hi-smart-perf-host-extend目录下,找到stop.bat文件,右键选择以管理员身份运行,即可关闭扩展服务。

- 备注:当前扩展服务版本为1.1.2,如果本地存在以其他方式安装的非正式版本,请手动关闭扩展服务,并重新按照该指导安装 + 备注:当前扩展服务版本为1.1.3,如果本地存在以其他方式安装的非正式版本,请手动关闭扩展服务,并重新按照该指导安装

diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index fc9897fa..353ded18 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -143,7 +143,7 @@ export class WebSocketManager { updateMessage(decode: MessageParam): void { if (decode.cmd === Constants.GET_VERSION_CMD) { // 小于则升级 - let targetVersion = '1.1.2'; + let targetVersion = '1.1.3'; let currentVersion = new TextDecoder().decode(decode.data); let result = this.compareVersion(currentVersion, targetVersion); if (result === -1) { -- Gitee From 7b56730ceca350216e931102f6d9b0a279516d29 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 28 Apr 2025 11:44:17 +0800 Subject: [PATCH 05/51] =?UTF-8?q?fix:smaps=E6=B3=B3=E9=81=93=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E9=99=90=E5=88=B6=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- .../trace/component/chart/SpVmTrackerChart.ts | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/ide/src/trace/component/chart/SpVmTrackerChart.ts b/ide/src/trace/component/chart/SpVmTrackerChart.ts index c6a4b931..8c0d3f47 100644 --- a/ide/src/trace/component/chart/SpVmTrackerChart.ts +++ b/ide/src/trace/component/chart/SpVmTrackerChart.ts @@ -62,6 +62,12 @@ export class VmTrackerChart { static gpuWindowModule: number | null = null; //ns private smapsRecordTab: TabPaneSmapsRecord | undefined | null; private scratchId = -1; + private isExistsPurgeableTotal: Array = []; + private isExistsPurgeablePin: Array = []; + private isExistsGpuMemory: Array = []; + private isExistsGpuResource: Array = []; + private isExistsGraph: Array = []; + private isExistsGl: Array = []; constructor(trace: SpSystemTrace) { this.trace = trace; } @@ -78,15 +84,32 @@ export class VmTrackerChart { } } } - await this.initVmTrackerFolder(); - await this.initSMapsFolder(); - const rowNameList: Array = ['Dirty', 'Swapped', 'RSS', 'PSS', 'USS']; - for (const rowName of rowNameList) { - await this.initSmapsRows(rowName); - } + const result = await querySmapsExits(); + this.isExistsPurgeableTotal = await queryisExistsPurgeableData(this.memoryConfig.iPid, false); + this.isExistsPurgeablePin = await queryisExistsPurgeableData(this.memoryConfig.iPid, true); + this.isExistsGpuMemory = await queryisExistsGpuMemoryData(this.memoryConfig.iPid); + this.isExistsGpuResource = await queryisExistsGpuResourceData(this.scratchId); + this.isExistsGraph = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.graph_pss'"); + this.isExistsGl = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.gl_pss'"); const isExistsShm = await queryisExistsShmData(this.memoryConfig.iPid); const isExistsDma = await queryisExistsDmaData(this.memoryConfig.iPid); //@ts-ignore + if (result.length === 0 && isExistsShm[0].data_exists === 0 && isExistsDma[0].data_exists === 0 && this.isExistsPurgeableTotal[0].data_exists === 0 && + //@ts-ignore + this.isExistsPurgeablePin[0].data_exists === 0 && this.isExistsGpuMemory[0].data_exists === 0 && this.isExistsGpuResource[0].data_exists === 0 && + //@ts-ignore + this.isExistsGraph[0].data_exists === 0 && this.isExistsGl[0].data_exists === 0) { + return; + } + await this.initVmTrackerFolder(); + if (result.length > 0) { + await this.initSMapsFolder(); + const rowNameList: Array = ['Dirty', 'Swapped', 'RSS', 'PSS', 'USS']; + for (const rowName of rowNameList) { + await this.initSmapsRows(rowName); + } + } + //@ts-ignore if (isExistsShm[0].data_exists) { await this.initShmRows(); } @@ -99,37 +122,33 @@ export class VmTrackerChart { } private async initGpuData(): Promise { - const isExistsGpuMemory = await queryisExistsGpuMemoryData(this.memoryConfig.iPid); - const isExistsGpuResource = await queryisExistsGpuResourceData(this.scratchId); - const isExistsGraph = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.graph_pss'"); - const isExistsGl = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.gl_pss'"); if ( // @ts-ignore - isExistsGpuMemory[0].data_exists || + this.isExistsGpuMemory[0].data_exists || // @ts-ignore - isExistsGpuResource[0].data_exists || + this.isExistsGpuResource[0].data_exists || // @ts-ignore - isExistsGraph[0].data_exists || + this.isExistsGraph[0].data_exists || // @ts-ignore - isExistsGl[0].data_exists + this.isExistsGl[0].data_exists ) { await this.initGpuFolder(); // @ts-ignore - if (isExistsGpuMemory[0].data_exists) { + if (this.isExistsGpuMemory[0].data_exists) { await this.initGpuMemoryRow(); } // @ts-ignore - if (isExistsGpuResource[0].data_exists) { + if (this.isExistsGpuResource[0].data_exists) { await this.initGpuResourceRow(this.scratchId); } else { this.smapsRecordTab!.GLESHostCache = []; } // @ts-ignore - if (isExistsGraph[0].data_exists) { + if (this.isExistsGraph[0].data_exists) { await this.addGpuGraphRow(); } // @ts-ignore - if (isExistsGl[0].data_exists) { + if (this.isExistsGl[0].data_exists) { await this.addGpuGLRow(); await this.addGpuTotalRow(); await this.addGpuWindowRow(); @@ -334,12 +353,11 @@ export class VmTrackerChart { private initPurgeableVM = async (): Promise => { let time = new Date().getTime(); - const isExistsPurgeableTotal = await queryisExistsPurgeableData(this.memoryConfig.iPid, false); - const isExistsPurgeablePin = await queryisExistsPurgeableData(this.memoryConfig.iPid, true); //@ts-ignore - if (isExistsPurgeableTotal[0].data_exists) { + //@ts-ignore + if (this.isExistsPurgeableTotal[0].data_exists) { await this.initPurgeableTotal(); } //@ts-ignore - if (isExistsPurgeablePin[0].data_exists) { + if (this.isExistsPurgeablePin[0].data_exists) { await this.initPurgeablePin(); } let durTime = new Date().getTime() - time; -- Gitee From 7f7a5edcceaa9a1551b63b763360128036b174b6 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Thu, 17 Apr 2025 17:22:00 +0800 Subject: [PATCH 06/51] =?UTF-8?q?trace=E6=96=B0=E5=A2=9Etag=E3=80=81cat?= =?UTF-8?q?=E3=80=81args=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: JustinYT --- ide/src/doc/md/des_tables.md | 14 ++++- trace_streamer/src/base/string_help.cpp | 6 +- trace_streamer/src/base/string_help.h | 4 +- trace_streamer/src/filter/slice_filter.cpp | 13 +++-- trace_streamer/src/parser/common_types.h | 14 ++++- .../src/parser/print_event_parser.cpp | 57 ++++++++++++++++++- .../src/parser/print_event_parser.h | 1 + .../src/table/ftrace/callstack_table.cpp | 32 ++++++++++- .../ftrace/callstack_stdtype.cpp | 53 ++++++++++++++++- .../trace_stdtype/ftrace/callstack_stdtype.h | 31 +++++++++- trace_streamer/src/version.cpp | 4 +- 11 files changed, 208 insertions(+), 21 deletions(-) diff --git a/ide/src/doc/md/des_tables.md b/ide/src/doc/md/des_tables.md index ccca67b7..3e26dacc 100644 --- a/ide/src/doc/md/des_tables.md +++ b/ide/src/doc/md/des_tables.md @@ -18,7 +18,7 @@ TraceStreamer可以将trace数据源转化为易于理解和使用的数据库 | app_startup | 记录了应用启动相关数据| | args | 记录方法参数集合| | bio_latency_sample | 记录IO操作相关方法调用,及调用栈数据| -| callstack | 记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号| +| callstack | 记录调用堆栈和异步调用信息,其中depth仅在非异步调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,child_callid为子线程唯一号| | clk_event_filter | 记录时钟相关的信息| | clock_event_filter | 此结构用来维护时钟事件,cpu与唯一的ID做关联| | clock_snapshot | 时钟号和时间,时钟名的映射表| @@ -362,8 +362,13 @@ js_heap_sample:记录timeline的时间轴信息 |spanId |TEXT | |parentSpanId |TEXT | |flag |TEXT | +|trace_level |TEXT | +|trace_tag |TEXT | +|custom_category |TEXT | +|custom_args |TEXT | +|child_callid |INT | #### 表描述 -记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步的调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号。 +记录调用堆栈和异步调用信息,其中depth仅在非异步的调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,child_callid为子线程唯一号。 #### 字段详细描述 - id: 唯一标识 - ts: 数据事件上报时间戳 @@ -379,6 +384,11 @@ js_heap_sample:记录timeline的时间轴信息 - spanId:分布式调用关联关系,当前帧的id - parentSpanId: 分布式调用关联关系,当前帧的parent的SpanId,对应当前表的spandId - flag:C表示分布式调用发送方,S表示接受方 +- trace_level:决定trace的等级,log和nolog等级不同,其中log表示详细记录所有相关的调用信息,nolog 表示不记录 +- trace_tag:Tag标签,标识请求的来源或类型 +- custom_category:聚合标签,用于关联同类信息 +- custom_args:自定义参数,用于存储与调用相关的额外信息 +- child_callid:当为异步调用,此时callid为进程唯一号,child_callid为子线程唯一号,反之为无效值 ### clk_event_filter表 #### 表结构 diff --git a/trace_streamer/src/base/string_help.cpp b/trace_streamer/src/base/string_help.cpp index f18316d3..8fd7dbdd 100644 --- a/trace_streamer/src/base/string_help.cpp +++ b/trace_streamer/src/base/string_help.cpp @@ -44,19 +44,21 @@ bool EndWith(const std::string &str, const std::string &res) return str.compare(str.size() - res.size(), res.size(), res) == 0; } -std::vector SplitStringToVec(const std::string &str, const std::string &pat) +std::vector SplitStringToVec(const std::string &str, const std::string &pat, uint32_t expectedCount) { std::vector result; size_t curPos = 0; size_t strSize = str.size(); size_t patSize = pat.size(); + uint32_t endFlag = 0; while (curPos < strSize) { auto patPos = str.find(pat, curPos); - if (patPos == std::string::npos) { + if (patPos == std::string::npos || endFlag == expectedCount) { break; } result.emplace_back(str.substr(curPos, patPos - curPos)); curPos = patPos + patSize; + endFlag++; } if (curPos < strSize) { result.emplace_back(str.substr(curPos)); diff --git a/trace_streamer/src/base/string_help.h b/trace_streamer/src/base/string_help.h index c1046410..df4bb6a7 100644 --- a/trace_streamer/src/base/string_help.h +++ b/trace_streamer/src/base/string_help.h @@ -23,7 +23,9 @@ namespace SysTuning { namespace base { char *GetDemangleSymbolIndex(const char *mangled); -std::vector SplitStringToVec(const std::string &str, const std::string &pat); +std::vector SplitStringToVec(const std::string &str, + const std::string &pat, + uint32_t expectedCount = UINT32_MAX); bool StartWith(const std::string &str, const std::string &res); bool EndWith(const std::string &str, const std::string &res); std::string FormatString(const char *p); diff --git a/trace_streamer/src/filter/slice_filter.cpp b/trace_streamer/src/filter/slice_filter.cpp index 00ad01d3..0e14097f 100644 --- a/trace_streamer/src/filter/slice_filter.cpp +++ b/trace_streamer/src/filter/slice_filter.cpp @@ -325,9 +325,13 @@ size_t SliceFilter::StartSlice(uint64_t timeStamp, uint32_t depth = stack.size(); auto slices = traceDataCache_->GetInternalSlicesData(); uint32_t parentId = depth == 0 ? INVALID_UINT32 : slices->IdsData()[stack.back().index]; - CallStackInternalRow callStackInternalRow = {sliceData.timeStamp, static_cast(sliceData.duration), - sliceData.internalTid, sliceData.cat, - sliceData.name, 0}; + CallStackInternalRow callStackInternalRow = {sliceData.timeStamp, + static_cast(sliceData.duration), + sliceData.internalTid, + sliceData.cat, + sliceData.name, + 0, + INVALID_UINT32}; size_t index = slices->AppendInternalSlice(callStackInternalRow, parentId); if (depth >= std::numeric_limits::max()) { return SIZE_MAX; @@ -464,8 +468,9 @@ uint64_t SliceFilter::StartAsyncSlice(uint64_t timeStamp, // the IDE need a depth to paint call slice in different position of the canvas, the depth of async call // do not mean the parent-to-child relationship, it is different from no-async call uint8_t depth = 0; + uint32_t childCallid = parentId; CallStackInternalRow callStackInternalRow = {timeStamp, static_cast(-1), internalTid, cat, nameIndex, - depth}; + depth, childCallid}; size_t index = slices->AppendInternalAsyncSlice(callStackInternalRow, cookie, parentId); asyncEventFilterMap_.insert(std::make_pair(asyncEventSize_, AsyncEvent{timeStamp, index})); return index; diff --git a/trace_streamer/src/parser/common_types.h b/trace_streamer/src/parser/common_types.h index 16a3e3bd..76d48f77 100644 --- a/trace_streamer/src/parser/common_types.h +++ b/trace_streamer/src/parser/common_types.h @@ -90,7 +90,11 @@ public: args_(point.args_), funcPrefixId_(point.funcPrefixId_), funcPrefix_(point.funcPrefix_), - funcArgs_(point.funcArgs_) + funcArgs_(point.funcArgs_), + traceLevel_(point.traceLevel_), + traceTagId_(point.traceTagId_), + customCategoryId_(point.customCategoryId_), + customArgsId_(point.customArgsId_) { } void operator=(const TracePoint &point) @@ -108,6 +112,10 @@ public: funcPrefixId_ = point.funcPrefixId_; funcPrefix_ = point.funcPrefix_; funcArgs_ = point.funcArgs_; + traceLevel_ = point.traceLevel_; + traceTagId_ = point.traceTagId_; + customCategoryId_ = point.customCategoryId_; + customArgsId_ = point.customArgsId_; } char phase_ = '\0'; uint32_t tgid_ = 0; @@ -123,6 +131,10 @@ public: uint32_t funcPrefixId_ = 0; std::string funcPrefix_ = ""; std::string funcArgs_ = ""; + std::string traceLevel_ = ""; + DataIndex traceTagId_ = INVALID_UINT64; + DataIndex customCategoryId_ = INVALID_UINT64; + DataIndex customArgsId_ = INVALID_UINT64; }; enum class SplitDataDataType { SPLIT_FILE_DATA = 0, SPLIT_FILE_JSON }; diff --git a/trace_streamer/src/parser/print_event_parser.cpp b/trace_streamer/src/parser/print_event_parser.cpp index a7271814..6d324cbb 100644 --- a/trace_streamer/src/parser/print_event_parser.cpp +++ b/trace_streamer/src/parser/print_event_parser.cpp @@ -24,6 +24,9 @@ namespace SysTuning { namespace TraceStreamer { const uint8_t POINT_LENGTH = 1; const uint8_t MAX_POINT_LENGTH = 2; +const uint8_t CATEGORY_INDEX = 2; +const uint8_t PARSER_SYNC_SUM = 2; +const uint8_t PARSER_ASYNC_SUM = 3; PrintEventParser::PrintEventParser(TraceDataCache *dataCache, const TraceStreamerFilters *filter) : EventParserBase(dataCache, filter) { @@ -105,6 +108,10 @@ void PrintEventParser::ParseBeginEvent(const std::string &comm, // add distributed data traceDataCache_->GetInternalSlicesData()->SetDistributeInfo(index, point.chainId_, point.spanId_, point.parentSpanId_, point.flag_); + + // add traceMeta data + traceDataCache_->GetInternalSlicesData()->SetTraceMetadata(index, point.traceLevel_, point.traceTagId_, + point.customArgsId_); if (HandleFrameSliceBeginEvent(point.funcPrefixId_, index, point.funcArgs_, line)) { return; } @@ -136,9 +143,16 @@ void PrintEventParser::ParseStartEvent(const std::string &comm, auto cookie = static_cast(point.value_); auto index = streamFilters_->sliceFilter_->StartAsyncSlice(ts, pid, point.tgid_, cookie, traceDataCache_->GetDataIndex(point.name_)); - if (point.name_ == onFrameQueeuStartEvent_ && index != INVALID_UINT64) { + if (index == INVALID_UINT64) { + return; + } + // add traceMeta data + traceDataCache_->GetInternalSlicesData()->SetTraceMetadata(index, point.traceLevel_, point.traceTagId_, + point.customArgsId_, point.customCategoryId_); + + if (point.name_ == onFrameQueeuStartEvent_) { OnFrameQueueStart(ts, index, point.tgid_); - } else if (traceDataCache_->AnimationTraceEnabled() && index != INVALID_UINT64 && + } else if (traceDataCache_->AnimationTraceEnabled() && (base::EndWith(comm, onAnimationProcEvent_) || base::EndWith(comm, newOnAnimationProcEvent_))) { // the comm is taskName streamFilters_->animationFilter_->StartAnimationEvent(line, point, index); @@ -247,6 +261,36 @@ std::string_view PrintEventParser::GetPointNameForBegin(std::string_view pointSt return name; } +void PrintEventParser::ParseSplitTraceMetaData(const std::string &dataStr, TracePoint &outPoint, bool isAsynEvent) const +{ + std::string metaDataStr = base::Strip(dataStr); + uint32_t expectedCount = isAsynEvent ? PARSER_ASYNC_SUM : PARSER_SYNC_SUM; + std::vector traceMetaDatas = base::SplitStringToVec(metaDataStr, "|", expectedCount); + if (traceMetaDatas.size() <= 1) { + TS_LOGD("traceMetaDatas size: %zu, dataStr: %s", traceMetaDatas.size(), dataStr.c_str()); + return; + } + + std::string &marker = traceMetaDatas[1]; + if (!marker.empty()) { + outPoint.traceLevel_ = marker.substr(0, 1); + if (marker.size() > 1) { + std::string traceTag = marker.substr(1); + outPoint.traceTagId_ = traceDataCache_->GetDataIndex(traceTag); + } + } + + if (isAsynEvent && traceMetaDatas.size() > CATEGORY_INDEX) { + std::string customCategory = traceMetaDatas[CATEGORY_INDEX]; + outPoint.customCategoryId_ = traceDataCache_->GetDataIndex(customCategory); + } + + if (traceMetaDatas.size() > expectedCount) { + std::string customArgs = traceMetaDatas[expectedCount]; + outPoint.customArgsId_ = traceDataCache_->GetDataIndex(customArgs); + } +} + ParseResult PrintEventParser::HandlerB(std::string_view pointStr, TracePoint &outPoint, size_t tGidlength) const { outPoint.name_ = GetPointNameForBegin(pointStr, tGidlength); @@ -274,6 +318,9 @@ ParseResult PrintEventParser::HandlerB(std::string_view pointStr, TracePoint &ou } else { outPoint.funcPrefixId_ = traceDataCache_->GetDataIndex(outPoint.name_); } + + // traceMetaDatasSrt: H:name|%X%TAG|customArgs + ParseSplitTraceMetaData(outPoint.name_, outPoint, false); } return PARSE_SUCCESS; } @@ -535,7 +582,11 @@ ParseResult PrintEventParser::HandlerCSF(std::string_view pointStr, TracePoint & outPoint.categoryGroup_ = std::string_view(pointStr.data() + valuePipe + 1, groupLen); } - + // traceMetaDatasSrt: taskId|%X%TAG|customCategory|customArgs + std::string metaDataStr(pointStr.data() + valueIndex); + if (outPoint.phase_ == 'S') { + ParseSplitTraceMetaData(metaDataStr, outPoint, true); + } return PARSE_SUCCESS; } diff --git a/trace_streamer/src/parser/print_event_parser.h b/trace_streamer/src/parser/print_event_parser.h index 2a6aab55..4fbb1634 100644 --- a/trace_streamer/src/parser/print_event_parser.h +++ b/trace_streamer/src/parser/print_event_parser.h @@ -53,6 +53,7 @@ public: void Finish(); void SetTraceType(TraceFileType traceType); void SetTraceClockId(BuiltinClocks clock); + void ParseSplitTraceMetaData(const std::string &dataStr, TracePoint &outPoint, bool isAsynEvent) const; private: using FrameFuncCall = std::function; diff --git a/trace_streamer/src/table/ftrace/callstack_table.cpp b/trace_streamer/src/table/ftrace/callstack_table.cpp index 48a1bda1..ff2d133e 100644 --- a/trace_streamer/src/table/ftrace/callstack_table.cpp +++ b/trace_streamer/src/table/ftrace/callstack_table.cpp @@ -34,7 +34,12 @@ enum class Index : int32_t { CHAIN_IDS, SPAN_IDS, PARENT_SPAN_IDS, - FLAGS + FLAGS, + TRACE_LEVEL, + TRACE_TAG, + CUSTOM_CATEGORY, + CUSTOM_ARGS, + CHILD_CALLID }; CallStackTable::CallStackTable(const TraceDataCache *dataCache) : TableBase(dataCache) { @@ -55,6 +60,11 @@ CallStackTable::CallStackTable(const TraceDataCache *dataCache) : TableBase(data tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT")); tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT")); tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("trace_level", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("trace_tag", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("custom_category", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("custom_args", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("child_callid", "INTEGER")); tablePriKey_.push_back("callid"); tablePriKey_.push_back("ts"); tablePriKey_.push_back("depth"); @@ -215,6 +225,26 @@ void CallStackTable::Cursor::HandleTypeColumns(int32_t col) const SetTypeColumnTextNotEmpty(slicesObj_.Flags()[CurrentRow()].empty(), slicesObj_.Flags()[CurrentRow()].c_str()); break; + case Index::TRACE_LEVEL: + SetTypeColumnTextNotEmpty(slicesObj_.TraceLevelsData()[CurrentRow()].empty(), + slicesObj_.TraceLevelsData()[CurrentRow()].c_str()); + break; + case Index::TRACE_TAG: + SetTypeColumnText(slicesObj_.TraceTagsData()[CurrentRow()], INVALID_UINT64); + break; + case Index::CUSTOM_CATEGORY: + SetTypeColumnText(slicesObj_.CustomCategorysData()[CurrentRow()], INVALID_UINT64); + break; + case Index::CUSTOM_ARGS: + SetTypeColumnText(slicesObj_.CustomArgsData()[CurrentRow()], INVALID_UINT64); + break; + case Index::CHILD_CALLID: { + if (slicesObj_.ChildCallidData()[CurrentRow()].has_value()) { + sqlite3_result_int64(context_, + static_cast(slicesObj_.ChildCallidData()[CurrentRow()].value())); + } + break; + } default: TS_LOGF("Unregistered column : %d", col); break; diff --git a/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.cpp b/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.cpp index b13386b5..3bbbe4b8 100644 --- a/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.cpp +++ b/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.cpp @@ -21,8 +21,10 @@ size_t CallStack::AppendInternalAsyncSlice(const CallStackInternalRow &callStack const std::optional &parentId) { AppendCommonInfo(callStackInternalRow.startT, callStackInternalRow.durationNs, callStackInternalRow.internalTid); - AppendCallStack(callStackInternalRow.cat, callStackInternalRow.name, callStackInternalRow.depth, parentId); + AppendCallStack(callStackInternalRow.cat, callStackInternalRow.name, callStackInternalRow.depth, + callStackInternalRow.childCallid, parentId); AppendDistributeInfo(); + AppendTraceMetadata(); cookies_.emplace_back(cookid); ids_.emplace_back(id_++); return Size() - 1; @@ -31,10 +33,12 @@ size_t CallStack::AppendInternalSlice(const CallStackInternalRow &callStackInter const std::optional &parentId) { AppendCommonInfo(callStackInternalRow.startT, callStackInternalRow.durationNs, callStackInternalRow.internalTid); - AppendCallStack(callStackInternalRow.cat, callStackInternalRow.name, callStackInternalRow.depth, parentId); + AppendCallStack(callStackInternalRow.cat, callStackInternalRow.name, callStackInternalRow.depth, + callStackInternalRow.childCallid, parentId); ids_.emplace_back(id_++); cookies_.emplace_back(INVALID_INT64); AppendDistributeInfo(); + AppendTraceMetadata(); return Size() - 1; } @@ -45,12 +49,17 @@ void CallStack::AppendCommonInfo(uint64_t startT, uint64_t durationNs, InternalT callIds_.emplace_back(internalTid); colorIndexs_.emplace_back(0); } -void CallStack::AppendCallStack(DataIndex cat, DataIndex name, uint8_t depth, std::optional parentId) +void CallStack::AppendCallStack(DataIndex cat, + DataIndex name, + uint8_t depth, + std::optional childCallid, + std::optional parentId) { parentIds_.emplace_back(parentId); cats_.emplace_back(cat); names_.emplace_back(name); depths_.emplace_back(depth); + childCallid_.emplace_back(childCallid); } void CallStack::SetDistributeInfo(size_t index, const std::string &chainId, @@ -64,6 +73,17 @@ void CallStack::SetDistributeInfo(size_t index, flags_[index] = flag; argSet_[index] = INVALID_UINT32; } +void CallStack::SetTraceMetadata(size_t index, + const std::string &traceLevel, + const DataIndex &tag, + const DataIndex &customArg, + const DataIndex &customCategory) +{ + traceLevels_[index] = traceLevel; + traceTags_[index] = tag; + customArgs_[index] = customArg; + customCategorys_[index] = customCategory; +} void CallStack::AppendDistributeInfo() { chainIds_.emplace_back(""); @@ -72,6 +92,13 @@ void CallStack::AppendDistributeInfo() flags_.emplace_back(""); argSet_.emplace_back(INVALID_UINT32); } +void CallStack::AppendTraceMetadata() +{ + traceLevels_.emplace_back(""); + traceTags_.emplace_back(INVALID_UINT64); + customArgs_.emplace_back(INVALID_UINT64); + customCategorys_.emplace_back(INVALID_UINT64); +} void CallStack::SetDuration(size_t index, uint64_t timeStamp) { durs_[index] = timeStamp - timeStamps_[index]; @@ -161,5 +188,25 @@ const std::deque &CallStack::ArgSetIdsData() const { return argSet_; } +const std::deque &CallStack::TraceLevelsData() const +{ + return traceLevels_; +} +const std::deque &CallStack::TraceTagsData() const +{ + return traceTags_; +} +const std::deque &CallStack::CustomCategorysData() const +{ + return customCategorys_; +} +const std::deque &CallStack::CustomArgsData() const +{ + return customArgs_; +} +const std::deque> &CallStack::ChildCallidData() const +{ + return childCallid_; +} } // namespace TraceStdtype } // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.h b/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.h index 033d25db..07b5322b 100644 --- a/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.h +++ b/trace_streamer/src/trace_data/trace_stdtype/ftrace/callstack_stdtype.h @@ -29,6 +29,7 @@ struct CallStackInternalRow { DataIndex cat = INVALID_UINT64; DataIndex name = INVALID_UINT64; uint8_t depth = INVALID_UINT8; + uint32_t childCallid = INVALID_UINT32; }; class CallStack : public CacheBase, public CpuCacheBase, public BatchCacheBase { public: @@ -43,7 +44,13 @@ public: const std::string &parentSpanId, const std::string &flag); void AppendDistributeInfo(); + void AppendTraceMetadata(); void SetDuration(size_t index, uint64_t timeStamp); + void SetTraceMetadata(size_t index, + const std::string &traceLevel, + const DataIndex &tag, + const DataIndex &customArg, + const DataIndex &customCategory = INVALID_UINT64); void SetDurationWithFlag(size_t index, uint64_t timeStamp); void SetFlag(size_t index, uint8_t flag); void SetDurationEx(size_t index, uint32_t dur); @@ -67,11 +74,17 @@ public: parentSpanIds_.clear(); flags_.clear(); argSet_.clear(); + traceLevels_.clear(); + traceTags_.clear(); + customCategorys_.clear(); + customArgs_.clear(); + childCallid_.clear(); } void ClearExportedData() override { EraseElements(timeStamps_, ids_, durs_, cats_, cookies_, colorIndexs_, callIds_, names_, depths_, chainIds_, - spanIds_, parentSpanIds_, flags_, argSet_); + spanIds_, parentSpanIds_, flags_, argSet_, traceLevels_, traceTags_, customCategorys_, + customArgs_, childCallid_); } const std::deque> &ParentIdData() const; const std::deque &CatsData() const; @@ -85,10 +98,19 @@ public: const std::deque &ParentSpanIds() const; const std::deque &Flags() const; const std::deque &ArgSetIdsData() const; + const std::deque &TraceLevelsData() const; + const std::deque &TraceTagsData() const; + const std::deque &CustomCategorysData() const; + const std::deque &CustomArgsData() const; + const std::deque> &ChildCallidData() const; private: void AppendCommonInfo(uint64_t startT, uint64_t durationNs, InternalTid internalTid); - void AppendCallStack(DataIndex cat, DataIndex name, uint8_t depth, std::optional parentId); + void AppendCallStack(DataIndex cat, + DataIndex name, + uint8_t depth, + std::optional childCallid, + std::optional parentId); private: std::deque> parentIds_; @@ -103,6 +125,11 @@ private: std::deque parentSpanIds_ = {}; std::deque flags_ = {}; std::deque argSet_ = {}; + std::deque traceLevels_ = {}; + std::deque traceTags_ = {}; + std::deque customCategorys_ = {}; + std::deque customArgs_ = {}; + std::deque> childCallid_; }; } // namespace TraceStdtype } // namespace SysTuning diff --git a/trace_streamer/src/version.cpp b/trace_streamer/src/version.cpp index 9544e649..7a8226dd 100644 --- a/trace_streamer/src/version.cpp +++ b/trace_streamer/src/version.cpp @@ -17,7 +17,7 @@ namespace SysTuning { namespace TraceStreamer { size_t g_loadSize = 0; size_t g_fileSize = 0; -const std::string TRACE_STREAMER_VERSION = "4.2.9"; // version -const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/1/2"; // publish datetime +const std::string TRACE_STREAMER_VERSION = "4.3.2"; // version +const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/4/24"; // publish datetime } // namespace TraceStreamer } // namespace SysTuning -- Gitee From eb35438bccf580e48def6f3ad897abfdc2822656 Mon Sep 17 00:00:00 2001 From: zhangzepeng Date: Wed, 7 May 2025 11:03:31 +0800 Subject: [PATCH 07/51] =?UTF-8?q?trace=5Fstreamer=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzepeng --- trace_streamer/pare_third_party.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/trace_streamer/pare_third_party.sh b/trace_streamer/pare_third_party.sh index 498c209f..d5519354 100755 --- a/trace_streamer/pare_third_party.sh +++ b/trace_streamer/pare_third_party.sh @@ -30,7 +30,7 @@ cd third_party if [ ! -f "sqlite/BUILD.gn" ];then rm -rf sqlite - git clone git@gitee.com:openharmony/third_party_sqlite.git + git clone https://gitee.com/openharmony/third_party_sqlite.git if [ -d "third_party_sqlite" ];then mv third_party_sqlite sqlite cd sqlite @@ -41,7 +41,7 @@ if [ ! -f "sqlite/BUILD.gn" ];then fi if [ ! -f "protobuf/BUILD.gn" ];then rm -rf protobuf - git clone git@gitee.com:openharmony/third_party_protobuf.git + git clone https://gitee.com/openharmony/third_party_protobuf.git if [ -d "third_party_protobuf" ];then mv third_party_protobuf protobuf cd protobuf @@ -53,7 +53,7 @@ fi if [ ! -f "zlib/BUILD.gn" ];then rm -rf zlib - git clone --depth=1 git@gitee.com:openharmony/third_party_zlib.git + git clone --depth=1 https://gitee.com/openharmony/third_party_zlib.git if [ -d "third_party_zlib" ];then mv third_party_zlib zlib $cp ../prebuilts/patch_zlib/zlibbuild.gn zlib/BUILD.gn @@ -62,7 +62,7 @@ fi if [ ! -f "bzip2/BUILD.gn" ];then rm -rf bzip2 - git clone --depth=1 git@gitee.com:openharmony/third_party_bzip2.git + git clone --depth=1 https://gitee.com/openharmony/third_party_bzip2.git if [ -d "third_party_bzip2" ];then mv third_party_bzip2 bzip2 $cp ../prebuilts/patch_bzip2/bzip2build.gn bzip2/BUILD.gn @@ -74,7 +74,7 @@ fi if [ ! -f "googletest/BUILD.gn" ];then rm -rf googletest - git clone --depth=1 git@gitee.com:openharmony/third_party_googletest.git + git clone --depth=1 https://gitee.com/openharmony/third_party_googletest.git if [ -d "third_party_googletest" ];then mv third_party_googletest googletest $cp ../prebuilts/patch_googletest/googletestbuild.gn ../third_party/googletest/BUILD.gn @@ -84,7 +84,7 @@ fi if [ ! -f "json/BUILD.gn" ];then rm -rf json - git clone --depth=1 git@gitee.com:openharmony/third_party_json.git + git clone --depth=1 https://gitee.com/openharmony/third_party_json.git if [ -d "third_party_json" ];then mv third_party_json json fi @@ -92,7 +92,7 @@ fi if [ ! -f "libunwind/BUILD.gn" ];then rm -rf libunwind - git clone git@gitee.com:openharmony/third_party_libunwind.git + git clone https://gitee.com/openharmony/third_party_libunwind.git if [ -d "third_party_libunwind" ];then mv third_party_libunwind libunwind cd libunwind @@ -113,7 +113,7 @@ fi if [ ! -d "perf_include/hiviewdfx/faultloggerd" ];then rm -rf hiviewdfx_faultloggerd perf_include/hiviewdfx/faultloggerd mkdir -p perf_include/hiviewdfx/faultloggerd/interfaces/innerkits - git clone git@gitee.com:openharmony/hiviewdfx_faultloggerd.git + git clone https://gitee.com/openharmony/hiviewdfx_faultloggerd.git cd hiviewdfx_faultloggerd git reset --hard 7296f69c0d418cd9353638f3117296e4b494e4e5 cd .. @@ -151,7 +151,7 @@ if [ ! -d "perf_include/hiviewdfx/faultloggerd" ];then fi if [ ! -f "hiperf/BUILD.gn" ];then rm -rf hiperf developtools_hiperf - git clone git@gitee.com:openharmony/developtools_hiperf.git + git clone https://gitee.com/openharmony/developtools_hiperf.git cd developtools_hiperf git reset --hard 9d189f41d76c1ae6e8e12238aef5ef5b8cdbc09f cd .. @@ -189,13 +189,13 @@ fi if [ ! -f "bounds_checking_function/BUILD.gn" ];then rm -rf bounds_checking_function - git clone --depth=1 git@gitee.com:openharmony/third_party_bounds_checking_function.git bounds_checking_function + git clone --depth=1 https://gitee.com/openharmony/third_party_bounds_checking_function.git bounds_checking_function $cp ../prebuilts/patch_bounds_checking_function/bounds_checking_functionbuild.gn bounds_checking_function/BUILD.gn fi if [ ! -d "commonlibrary" ];then rm -rf commonlibrary - git clone --depth=1 git@gitee.com:openharmony/commonlibrary_c_utils.git + git clone --depth=1 https://gitee.com/openharmony/commonlibrary_c_utils.git if [ -d "commonlibrary_c_utils" ];then mv commonlibrary_c_utils commonlibrary rm -rf commonlibrary_c_utils @@ -204,7 +204,7 @@ fi if [ ! -f "profiler/device/plugins/ftrace_plugin/include/ftrace_common_type.h" ];then rm -rf profiler - git clone --depth=1 git@gitee.com:openharmony/developtools_profiler.git + git clone --depth=1 https://gitee.com/openharmony/developtools_profiler.git if [ -d "developtools_profiler" ];then mkdir -p profiler/device/plugins/ftrace_plugin/include $cp developtools_profiler/device/plugins/ftrace_plugin/include/ftrace_common_type.h profiler/device/plugins/ftrace_plugin/include @@ -215,7 +215,7 @@ fi if [ ! -d "llvm-project" ];then rm -rf llvm-project - git clone --depth=1 git@gitee.com:openharmony/third_party_llvm-project.git + git clone --depth=1 https://gitee.com/openharmony/third_party_llvm-project.git if [ -d "third_party_llvm-project" ];then mv third_party_llvm-project llvm-project cd llvm-project -- Gitee From 907040e47f87f1a8000d7d9b1c64b0190d9a55bb Mon Sep 17 00:00:00 2001 From: danghongquan Date: Sat, 10 May 2025 16:20:42 +0800 Subject: [PATCH 08/51] =?UTF-8?q?feat:=E9=80=82=E9=85=8Dnative=20meomory?= =?UTF-8?q?=20so=20=E5=8F=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- trace_streamer/src/filter/hook_filter/native_hook_filter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trace_streamer/src/filter/hook_filter/native_hook_filter.cpp b/trace_streamer/src/filter/hook_filter/native_hook_filter.cpp index 8426e70e..c666fcf7 100644 --- a/trace_streamer/src/filter/hook_filter/native_hook_filter.cpp +++ b/trace_streamer/src/filter/hook_filter/native_hook_filter.cpp @@ -32,6 +32,7 @@ NativeHookFilter::NativeHookFilter(TraceDataCache *dataCache, const TraceStreame invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libc++.so")); invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-aarch64.so.1")); invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-arm.so.1")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libdfmalloc.z.so")); hookPluginData_->set_name("nativehook"); commHookData_.datas = std::make_unique(); addrToAllocEventRow_ = traceDataCache_->GetNativeHookData()->GetAddrToAllocEventRow(); -- Gitee From 0de2a99b5c0332770c3a93b8afb7514274b6eb3c Mon Sep 17 00:00:00 2001 From: danghongquan Date: Sat, 10 May 2025 16:36:03 +0800 Subject: [PATCH 09/51] =?UTF-8?q?fix:=E7=89=B9=E6=AE=8A=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E4=B8=8B=E7=81=AB=E7=84=B0=E5=9B=BE=E5=87=BA=E7=8E=B0=E7=B4=AB?= =?UTF-8?q?=E8=89=B2=EF=BC=8C=E6=95=B0=E6=8D=AE=E7=B4=8A=E4=B9=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/trace/component/chart/FrameChart.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ide/src/trace/component/chart/FrameChart.ts b/ide/src/trace/component/chart/FrameChart.ts index 8255fec2..9c0bb5d8 100644 --- a/ide/src/trace/component/chart/FrameChart.ts +++ b/ide/src/trace/component/chart/FrameChart.ts @@ -232,6 +232,7 @@ export class FrameChart extends BaseElement { private clearOtherDisplayInfo(node: ChartStruct): void { for (const children of node.children) { if (children.isChartSelect) { + children.isChartSelect = false; this.clearOtherDisplayInfo(children); continue; } @@ -737,9 +738,9 @@ export class FrameChart extends BaseElement { this.setSelectStatusRecursive(ChartStruct.lastSelectFuncStruct!, false); } // 递归设置点选的parent,children为点选状态 + this.calDrawArgs(false); this.setSelectStatusRecursive(ChartStruct.selectFuncStruct!, true); - this.calDrawArgs(false); this.calculateChartData(); } -- Gitee From df3a8a53687a9a415a431815ef920ed93f3638e9 Mon Sep 17 00:00:00 2001 From: liufei Date: Sat, 10 May 2025 18:18:59 +0800 Subject: [PATCH 10/51] =?UTF-8?q?feat:hiperf=5Ffunc=E9=A1=B5=EF=BC=8C?= =?UTF-8?q?=E8=BD=ACsystem=20trace=E4=BD=BF=E7=94=A8=E9=87=8F=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- ide/src/trace/SpApplication.ts | 4 ++++ .../component/trace/sheet/hiperf/TabPanePerfAnalysis.ts | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index 0a703a33..0455a279 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -1756,6 +1756,10 @@ export class SpApplication extends BaseElement { if (attribute === 'Convert trace') { let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); querySelectors.forEach((item) => { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'convert_systrace', + action: 'convert_systrace', + }); if (item.getAttribute('title') === 'Convert to .systrace') { item!.setAttribute('icon', 'convert-loading'); item!.classList.add('pending'); diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index c04d2ce9..9b10f55a 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -27,6 +27,7 @@ import { TabpanePerfProfile } from './TabPerfProfile'; import { TabPanePerfAnalysisHtml } from './TabPanePerfAnalysis.html'; import { WebSocketManager } from '../../../../../webSocket/WebSocketManager'; import { Constants, TypeConstants } from '../../../../../webSocket/Constants'; +import { SpStatisticsHttpUtil } from '../../../../../statistics/util/SpStatisticsHttpUtil'; @element('tabpane-perf-analysis') export class TabPanePerfAnalysis extends BaseElement { @@ -591,6 +592,10 @@ export class TabPanePerfAnalysis extends BaseElement { } private functionClickEvent(it: unknown) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'hiperf_func', + action: 'hiperf_func', + }); // @ts-ignore this.perfAnalysisHeadTips?.innerHTML = ''; if (this.selectedTabfileName.indexOf('.an') === -1 && this.selectedTabfileName.indexOf('.so') === -1) { -- Gitee From e6a083a5488e5c692896b5c20177b9e1a17a86ae Mon Sep 17 00:00:00 2001 From: liufei Date: Mon, 12 May 2025 19:31:10 +0800 Subject: [PATCH 11/51] =?UTF-8?q?fix:=E8=BD=ACsystemtrace=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0.htrace=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: liufei --- ide/src/trace/SpApplication.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index 0455a279..dd3c76b9 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -1756,11 +1756,13 @@ export class SpApplication extends BaseElement { if (attribute === 'Convert trace') { let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); querySelectors.forEach((item) => { - SpStatisticsHttpUtil.addOrdinaryVisitAction({ - event: 'convert_systrace', - action: 'convert_systrace', - }); if (item.getAttribute('title') === 'Convert to .systrace') { + if(fileName.indexOf('.htrace')>0){ + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'convert_systrace', + action: 'convert_systrace', + }); + } item!.setAttribute('icon', 'convert-loading'); item!.classList.add('pending'); item!.style.fontKerning = ''; -- Gitee From 65eba36a4557c17409fef028d2cfd16023855557 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Tue, 13 May 2025 20:02:23 +0800 Subject: [PATCH 12/51] =?UTF-8?q?fix:HiSysEvent=E7=95=8C=E9=9D=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/trace/component/setting/SpHisysEvent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/trace/component/setting/SpHisysEvent.ts b/ide/src/trace/component/setting/SpHisysEvent.ts index 77956729..9cb549b5 100644 --- a/ide/src/trace/component/setting/SpHisysEvent.ts +++ b/ide/src/trace/component/setting/SpHisysEvent.ts @@ -64,7 +64,7 @@ export class SpHisysEvent extends BaseElement { } get sysEventConfigPath(): string { - return '/system/etc/hiview/hisysevent.def'; + return '//data/system/hiview/unzip_configs/sys_event_def/hisysevent.def'; } initElements(): void { -- Gitee From 29da017136904bd1f938946a071a7c891ccb4863 Mon Sep 17 00:00:00 2001 From: zhangzhuozhou Date: Wed, 14 May 2025 10:40:08 +0800 Subject: [PATCH 13/51] =?UTF-8?q?feat:=E9=80=82=E9=85=8Draw=20trace?= =?UTF-8?q?=E4=B8=ADsched=5Fwaking,sched=5Fwakeup=5Fnew=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhuozhou --- .../rawtrace_parser/ftrace_event_processor.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp b/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp index d6ffa3c2..5e83ac8c 100644 --- a/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp +++ b/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp @@ -312,7 +312,11 @@ bool FtraceEventProcessor::SchedWaking(FtraceEvent &ftraceEvent, uint8_t data[], auto schedWakingMsg = ftraceEvent.mutable_sched_waking_format(); schedWakingMsg->set_comm(FtraceFieldProcessor::HandleStrField(format.fields, index++, data, size)); schedWakingMsg->set_pid(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); - schedWakingMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + if (format.fields[index].size == NEW_SCHED_PRIO_SIZE) { + schedWakingMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + } else { + schedWakingMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + } schedWakingMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); schedWakingMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); return true; @@ -326,7 +330,11 @@ bool FtraceEventProcessor::SchedWakeupNew(FtraceEvent &ftraceEvent, auto wakeupNewMsg = ftraceEvent.mutable_sched_wakeup_new_format(); wakeupNewMsg->set_comm(FtraceFieldProcessor::HandleStrField(format.fields, index++, data, size)); wakeupNewMsg->set_pid(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); - wakeupNewMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + if (format.fields[index].size == NEW_SCHED_PRIO_SIZE) { + wakeupNewMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + } else { + wakeupNewMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + } wakeupNewMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); wakeupNewMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); return true; -- Gitee From 1352eb57615a58770da06aa10d55f3413c94aef5 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Wed, 14 May 2025 15:09:11 +0800 Subject: [PATCH 14/51] =?UTF-8?q?fix:hiperf=E6=95=B0=E6=8D=AE=E4=B8=AD?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E4=B8=BB=E7=BA=BF=E7=A8=8B=E6=97=B6=E6=9C=AA?= =?UTF-8?q?=E5=81=9A=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/trace/component/chart/SpHiPerf.ts | 6 +++--- .../trace/database/logic-worker/ProcedureLogicWorkerPerf.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ide/src/trace/component/chart/SpHiPerf.ts b/ide/src/trace/component/chart/SpHiPerf.ts index 23192717..9ffcc2f5 100644 --- a/ide/src/trace/component/chart/SpHiPerf.ts +++ b/ide/src/trace/component/chart/SpHiPerf.ts @@ -480,7 +480,7 @@ export class SpHiPerf { let array = this.group[key] as Array; let process = array.filter((th): boolean => th.pid === th.tid)[0]; let row = TraceRow.skeleton(); - row.rowId = `${process.pid}-Perf-Process`; + row.rowId = `${process ? process.pid : Number(key)}-Perf-Process`; row.index = index; row.rowType = TraceRow.ROW_TYPE_HIPERF_PROCESS; row.rowParentId = 'HiPerf'; @@ -491,14 +491,14 @@ export class SpHiPerf { row.addTemplateTypes('AppStartup'); } row.addTemplateTypes('HiPerf'); - row.name = `${process.processName || 'Process'} [${process.pid}]`; + row.name = `${process ? process.processName : 'Process'} [${process ? process.pid : Number(key)}]`; row.folderPaddingLeft = 6; row.style.height = '40px'; row.favoriteChangeHandler = this.trace.favoriteChangeHandler; row.selectChangeHandler = this.trace.selectChangeHandler; //@ts-ignore row.supplierFrame = (): Promise => { return hiperfProcessDataSender( - process.pid, + process ? process.pid : Number(key), row.drawType, this.maxCpuId + 1, SpHiPerf.stringResult?.fValue || 1, diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index ade2ef79..55eec1ba 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -1452,7 +1452,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { let callChains = [...this.callChainData[sample.sampleId]]; const lastCallChain = callChains[callChains.length - 1]; const threadName = this.threadData[sample.tid].threadName || 'Thread'; - const processName = this.threadData[sample.pid].threadName || 'Process'; + const processName = this.threadData[sample.pid] ? this.threadData[sample.pid].threadName : 'Process'; const funcName = this.dataCache.dataDict.get(lastCallChain.name as number); if ( //@ts-ignore -- Gitee From 47fdb79affc57b0328c11b406af5661b144e157d Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 16 May 2025 16:56:24 +0800 Subject: [PATCH 15/51] =?UTF-8?q?fix:=E6=9B=B4=E6=96=B0=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=9A=84=E7=89=88=E6=9C=AC=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/doc/quickstart_extensions.html | 2 +- ide/src/webSocket/WebSocketManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ide/src/doc/quickstart_extensions.html b/ide/src/doc/quickstart_extensions.html index d75add92..c39d01ea 100644 --- a/ide/src/doc/quickstart_extensions.html +++ b/ide/src/doc/quickstart_extensions.html @@ -811,7 +811,7 @@ 在hi-smart-perf-host-extend目录下,找到stop.bat文件,右键选择以管理员身份运行,即可关闭扩展服务。

- 备注:当前扩展服务版本为1.1.3,如果本地存在以其他方式安装的非正式版本,请手动关闭扩展服务,并重新按照该指导安装 + 备注:当前扩展服务版本为1.1.4,如果本地存在以其他方式安装的非正式版本,请手动关闭扩展服务,并重新按照该指导安装

diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index 353ded18..9318f1fa 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -143,7 +143,7 @@ export class WebSocketManager { updateMessage(decode: MessageParam): void { if (decode.cmd === Constants.GET_VERSION_CMD) { // 小于则升级 - let targetVersion = '1.1.3'; + let targetVersion = '1.1.4'; let currentVersion = new TextDecoder().decode(decode.data); let result = this.compareVersion(currentVersion, targetVersion); if (result === -1) { -- Gitee From 13024364d6ffc4a74f2f5b55b79e5ee0686dc397 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Mon, 12 May 2025 16:16:50 +0800 Subject: [PATCH 16/51] =?UTF-8?q?1.=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=B3=B3=E9=81=93=E5=9B=BE=E6=80=A7=E8=83=BD=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=9B2.=E8=A1=A5=E5=85=85=E9=83=A8=E5=88=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=B0=83=E7=94=A8=E5=90=8D=E7=A7=B0=E6=98=A0=E5=B0=84?= =?UTF-8?q?=203.=E5=A2=9E=E5=8A=A0=E8=A7=A3=E6=9E=90=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: JustinYT --- ide/src/config/config.json | 136 ++++ ide/src/trace/SpApplication.ts | 8 +- ide/src/trace/component/SpFlag.html.ts | 3 + ide/src/trace/component/SpFlags.ts | 142 ++++ ide/src/trace/component/SpSystemTrace.init.ts | 21 +- ide/src/trace/component/SpSystemTrace.ts | 8 +- .../trace/component/chart/SpProcessChart.ts | 4 +- .../component/trace/base/SysCallUtils.ts | 608 ++++++++++-------- ide/src/trace/database/TraceWorker.ts | 2 +- .../process/ThreadSysCallDataReceiver.ts | 34 +- .../process/ThreadSysCallDataSender.ts | 2 +- .../data-trafic/utils/AllMemoryCache.ts | 3 + .../ui-worker/ProcedureWorkerThreadSysCall.ts | 2 +- ide/webpack.config.js | 4 + 14 files changed, 680 insertions(+), 297 deletions(-) create mode 100644 ide/src/config/config.json diff --git a/ide/src/config/config.json b/ide/src/config/config.json new file mode 100644 index 00000000..6b4ff707 --- /dev/null +++ b/ide/src/config/config.json @@ -0,0 +1,136 @@ +{ + "_comment": "这是动效的相关打点", + "Animation": { + "_comment": "动效过程打点线程,render_service为并行化前的打点线程,RSUniRenderThre为并行化后的打点线程", + "animationProcEvents_": [ + "render_service", + "RSUniRenderThre" + ], + "_comment": "动效相关打点,H:LAUNCHER_APP_LAUNCH_FROM_ICON为桌面图标点击启动,H:LAUNCHER_APP_LAUNCH_FROM_NOTIFICATIONBAR为通知栏通知消息点击启动,H:LAUNCHER_APP_LAUNCH_FROM_NOTIFICATIONBAR_IN_LOCKSCREEN为锁屏通知消息点击启动,H:LAUNCHER_APP_LAUNCH_FROM_RECENT为多任务点击应用,H:LAUNCHER_APP_SWIPE_TO_HOME为HOME键返回桌面,H:LAUNCHER_APP_BACK_TO_HOME为Back键返回桌面,H:APP_TRANSITION_TO_OTHER_APP为应用切换到另一个应用,H:APP_TRANSITION_FROM_OTHER_APP为从另一个应用跳回,H:APP_LIST_FLING为应用中列表滑动", + "onAnimationStartEvents_": [ + "H:LAUNCHER_APP_LAUNCH_FROM_ICON", + "H:LAUNCHER_APP_LAUNCH_FROM_NOTIFICATIONBAR", + "H:LAUNCHER_APP_LAUNCH_FROM_NOTIFICATIONBAR_IN_LOCKSCREEN", + "H:LAUNCHER_APP_LAUNCH_FROM_RECENT", + "H:LAUNCHER_APP_SWIPE_TO_HOME", + "H:LAUNCHER_APP_BACK_TO_HOME", + "H:APP_TRANSITION_TO_OTHER_APP", + "H:APP_TRANSITION_FROM_OTHER_APP", + "H:APP_LIST_FLING" + ], + "_comment": "H:GenerateVsyncCount,用于计算设备的平均帧率,累计6次后输出平均帧率", + "frameRateCmd_": [ + "H:GenerateVsyncCount" + ], + "_comment": "H:RSJankStats::RecordAnimationDynamicFrameRate,用于更新动效的帧率,若存在此打点,则以这个打点为准,否则以H:Repaint为准", + "realFrameRateCmd_": [ + "H:RSJankStats::RecordAnimationDynamicFrameRate" + ], + "_comment": "H:Repaint(硬件合成器合成绘制),用于计算动效帧率", + "frameCountCmd_": [ + "H:Repaint" + ], + "_comment": "H:RSUniRender::Process:[WindowScene_和H:RSSurfaceRenderNodeDrawable::OnDraw:[WindowScene_用来获取动效帧数据的打点,其中H:RSUniRender::Process:[WindowScene_为并行化前打点", + "frameBeginCmd_": [ + "H:RSUniRender::Process:[WindowScene_", + "H:RSSurfaceRenderNodeDrawable::OnDraw:[WindowScene_" + ], + "_comment": "H:RSUniRender::Process:[SCBDesktop和H:RSSurfaceRenderNodeDrawable::OnDraw:[SCBDesktop用来获取设备的宽高,其中H:RSUniRender::Process:[SCBDesktop为并行化前打点", + "screenSizeCmd_": [ + "H:RSUniRender::Process:[SCBDesktop", + "H:RSSurfaceRenderNodeDrawable::OnDraw:[SCBDesktop" + ], + "_comment": "H:RSMainThread::DoComposition和H:RenderFrame用来获取动效帧的结束时间,其中H:RSMainThread::DoComposition为并行化前的打点", + "frameEndTimeCmd_": [ + "H:RenderFrame" + ], + "_comment": "H:PostAndWait, parallel type并行化的标志", + "parallelTypeCmd_": [ + "H:PostAndWait, parallel type" + ] + }, + "_comment": "这是启动场景的相关打点", + "AppStartup": { + "_comment": "启动第一阶段,手指点击", + "phase1": { + "pName": "ProcessTouchEvent", + "start": [ + "H:client dispatch touchId:" + ], + "end": [ + "H:OHOS::ErrCode OHOS::AAFwk::AbilityManagerClient::StartUIAbilityBySCB" + ] + }, + "_comment": "启动第二阶段,处理创建进程信息,创建窗口", + "phase2": { + "pName": "StartUIAbilityBySCB", + "start": [ + "H:OHOS::ErrCode OHOS::AAFwk::AbilityManagerClient::StartUIAbilityBySCB" + ], + "end": [ + "H:virtual void OHOS::AppExecFwk::AppMgrServiceInner::LoadAbility" + ] + }, + "_comment": "启动第三阶段,拉起应用进程", + "phase3": { + "pName": "LoadAbility", + "start": [ + "H:virtual void OHOS::AppExecFwk::AppMgrServiceInner::LoadAbility" + ], + "end": [ + "H:virtual void OHOS::AppExecFwk::AppMgrServiceInner::AttachApplication(const pid_t, const sptr &)##" + ] + }, + "_comment": "启动第四阶段,加载应用", + "phase4": { + "pName": "Application Launching", + "start": [ + "H:virtual void OHOS::AppExecFwk::AppMgrServiceInner::AttachApplication(const pid_t, const sptr &)##" + ], + "end": [ + "H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility(const std::shared_ptr &)##" + ] + }, + "_comment": "启动第五阶段,加载 UI Ability", + "phase5": { + "pName": "UI Ability Launching", + "start": [ + "H:void OHOS::AppExecFwk::MainThread::HandleLaunchAbility(const std::shared_ptr &)##" + ], + "end": [ + "H:void OHOS::AbilityRuntime::FAAbilityThread::HandleAbilityTransaction(const OHOS::AbilityRuntime::Want &, const OHOS::AbilityRuntime::LifeCycleStateInfo &, sptr)##", + "H:void OHOS::AbilityRuntime::UIAbilityThread::HandleAbilityTransaction" + ] + }, + "_comment": "启动第六阶段,应用进入前台", + "phase6": { + "pName": "UI Ability OnForeground", + "start": [ + "H:void OHOS::AbilityRuntime::FAAbilityThread::HandleAbilityTransaction(const OHOS::AbilityRuntime::Want &, const OHOS::AbilityRuntime::LifeCycleStateInfo &, sptr)##", + "H:void OHOS::AbilityRuntime::UIAbilityThread::HandleAbilityTransaction" + ], + "end": [ + "H:ReceiveVsync dataCount" + ] + } + }, + "_comment": "Flag 开关", + "config": { + "TaskPool": 0, + "AnimationAnalysis": 0, + "AppStartup": 0, + "SchedulingAnalysis": 0, + "BinderRunnable": 0, + "FfrtConvert": 0, + "HMKernel": 1, + "VSync": 0, + "Hangs Detection": 0, + "LTPO": 0, + "Start&Finish Trace Category": 0, + "UserPluginsRow": 0, + "CPU by Irq": 0, + "RawTraceCutStartTs": 1, + "AI": 0, + "System Calls": "" + } +} \ No newline at end of file diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index 0a703a33..0288314c 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -1114,7 +1114,7 @@ export class SpApplication extends BaseElement { let data = this.markPositionHandler(reader.result as ArrayBuffer); this.spSystemTrace!.loadDatabaseArrayBuffer( data, - '', + '', '', (command: string, _: number) => { this.setProgress(command); }, @@ -1173,6 +1173,7 @@ export class SpApplication extends BaseElement { } Promise.all([threadPool.init(traceType), threadPool2.init(traceType)]).then(() => { let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; + let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/config/config.json`; Promise.all([file1.arrayBuffer(), file2.arrayBuffer()]).then((bufArr) => { this.litSearch!.setPercent('ArrayBuffer loaded ', 2); SpApplication.loadingProgress = 0; @@ -1182,7 +1183,7 @@ export class SpApplication extends BaseElement { info('initData start Parse Data'); this.spSystemTrace!.loadDatabaseArrayBuffer( buf1, - wasmUrl, + wasmUrl, configUrl, (command: string, _: number) => this.setProgress(command), true, completeHandler, @@ -1238,13 +1239,14 @@ export class SpApplication extends BaseElement { info('read file onloadend'); this.litSearch!.setPercent('ArrayBuffer loaded ', 2); let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; + let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/config/config.json`; SpApplication.loadingProgress = 0; SpApplication.progressStep = 3; let data = this.markPositionHandler(reader.result as ArrayBuffer); info('initData start Parse Data'); this.spSystemTrace!.loadDatabaseArrayBuffer( data, - wasmUrl, + wasmUrl,configUrl, (command: string, _: number) => this.setProgress(command), false, completeHandler diff --git a/ide/src/trace/component/SpFlag.html.ts b/ide/src/trace/component/SpFlag.html.ts index 273c5cea..7c88577b 100644 --- a/ide/src/trace/component/SpFlag.html.ts +++ b/ide/src/trace/component/SpFlag.html.ts @@ -106,6 +106,9 @@ export const SpFlagHtml = `
diff --git a/ide/src/trace/component/SpFlags.ts b/ide/src/trace/component/SpFlags.ts index d3bf0845..e8ebe0f8 100644 --- a/ide/src/trace/component/SpFlags.ts +++ b/ide/src/trace/component/SpFlags.ts @@ -15,6 +15,9 @@ import { BaseElement, element } from '../../base-ui/BaseElement'; import { SpFlagHtml } from './SpFlag.html'; +import { LitSelectV } from '../../base-ui/select/LitSelectV'; +import { SysCallMap } from './trace/base/SysCallUtils'; + const NUM = '000000'; //vsync二级下拉选框对应的value和content const VSYNC_CONTENT = [ @@ -46,14 +49,71 @@ const CONFIG_STATE: unknown = { export class SpFlags extends BaseElement { private bodyEl: HTMLElement | undefined | null; private xiaoLubanEl: Element | null | undefined; + private systemCallSelect: LitSelectV | undefined | null; + private systemCallInput: HTMLInputElement | undefined | null; + private systemCallEventId: number[] = []; + private systemCallSwitch: HTMLSelectElement | undefined | null; + + + connectedCallback(): void { + this.systemCallInput?.addEventListener('mousedown', this.systemCallSelectMousedownHandler); + this.systemCallSelect?.addEventListener('blur', this.systemCallSelectBlurHandler); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + this.systemCallInput?.removeEventListener('mousedown', this.systemCallSelectMousedownHandler); + this.systemCallSelect?.removeEventListener('blur', this.systemCallSelectBlurHandler); + } initElements(): void { let parentElement = this.parentNode as HTMLElement; parentElement.style.overflow = 'hidden'; this.bodyEl = this.shadowRoot?.querySelector('.body'); this.initConfigList(); + this.systemCallSelect = this.shadowRoot?.querySelector("lit-select-v[title='SystemCall']"); + this.systemCallSwitch = this.shadowRoot?.querySelector("select[title='System Calls']"); + this.systemCallInput = this.systemCallSelect!.shadowRoot?.querySelector('input') as HTMLInputElement; + this.updateSystemCallSelect(); } + private updateSystemCallSelect(): void { + if (this.systemCallSwitch?.title === 'System Calls' && this.systemCallSwitch.selectedOptions[0].value === 'Enabled') { + this.systemCallSelect?.removeAttribute('disabled'); + this.systemCallSelect?.dataSource([], ''); + } else { + this.systemCallSelect?.setAttribute('disabled', 'disabled'); + this.systemCallSelect?.dataSource([], ''); + } + } + + private systemCallSelectBlurHandler = () => { + let systemCallSelectOptions = this.systemCallSelect!.shadowRoot?.querySelectorAll('.option'); + this.systemCallEventId = []; + systemCallSelectOptions!.forEach((option) => { + if (option.hasAttribute('selected')) { + const systemCallEventItem = Array.from(SysCallMap.entries()) + .find(([id, name]) => name === option.getAttribute('value')); + if (systemCallEventItem) { + this.handleSystemCallEventId(systemCallEventItem[0]); + } + } + }); + FlagsConfig.updateSystemcallEventId(this.systemCallEventId, 'SystemParsing'); + return this.systemCallEventId; + }; + + private handleSystemCallEventId = (systemCallEventId: number): void => { + this.systemCallEventId.push(systemCallEventId); + }; + + private systemCallSelectMousedownHandler = (): void => { + if (this.systemCallSwitch) + systemCallConfigList[0].selectArray = Array.from(SysCallMap.entries()) + .map(([id, name]) => `${name}`); + this.systemCallSelect?.dataSource(systemCallConfigList[0].selectArray, 'ALL-SystemCall') + }; + initHtml(): string { return SpFlagHtml; } @@ -102,6 +162,11 @@ export class SpFlags extends BaseElement { this.xiaoLubanEl?.removeAttribute('enabled'); } } + if (configSelect.title === 'System Calls' && configSelect.selectedOptions[0].value === 'Enabled') { + this.systemCallSelect?.removeAttribute('disabled'); + } else { + this.systemCallSelect?.setAttribute('disabled', 'disabled'); + } }); let userIdInput: HTMLInputElement | null | undefined = this.shadowRoot?.querySelector('#user_id_input'); if (configSelect.title === 'AI' && configSelect.selectedOptions[0].value === 'Enabled' && userIdInput?.value === '') { @@ -226,10 +291,51 @@ export class SpFlags extends BaseElement { configFooterDiv.appendChild(userIdInputEl); configDiv.appendChild(configFooterDiv); } + if (config.title === 'System Calls') { + let configFooterDiv = document.createElement('div'); + configFooterDiv.className = 'config_footer'; + let systemCallConfigEl = document.createElement('div'); + systemCallConfigEl.className = 'system-call-config'; + systemCallConfigList.forEach((config) => { + let systemCallConfigDiv = document.createElement('div'); + if (config.hidden) { + systemCallConfigDiv.className = 'systemCall-config-div hidden'; + } else { + systemCallConfigDiv.className = 'systemCall-config-div'; + } + switch (config.type) { + case 'select-multiple': + this.configTypeBySelectMultiple(config, systemCallConfigDiv); + break; + default: + break; + } + systemCallConfigEl.appendChild(systemCallConfigDiv); + }) + configFooterDiv.appendChild(systemCallConfigEl); + configDiv.appendChild(configFooterDiv); + } this.bodyEl!.appendChild(configDiv); }); } + private configTypeBySelectMultiple(config: unknown, systemCallConfigDiv: HTMLDivElement): void { + let html = ''; + //@ts-ignore + let placeholder = config.selectArray[0]; + html += ``; + //@ts-ignore + config.selectArray.forEach((value: string) => { + html += `${value}`; + }); + html += ''; + systemCallConfigDiv.innerHTML = systemCallConfigDiv.innerHTML + html; + } + private createPersonOption(list: unknown, key: string, config: unknown): HTMLDivElement { let configFooterDiv = document.createElement('div'); configFooterDiv.className = 'config_footer'; @@ -279,6 +385,7 @@ export type Params = { export class FlagsConfig { static FLAGS_CONFIG_KEY = 'FlagsConfig'; + static SYSTEM_PRASE = 'SystemParsing'; static DEFAULT_CONFIG: Array = [ { title: 'TaskPool', @@ -359,6 +466,12 @@ export class FlagsConfig { switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], describeContent: 'Start AI', addInfo: { userId: '' }, + }, + { + title: 'System Calls', + switchOptions: [{ option: 'Enabled' }, { option: 'Disabled', selected: true }], + describeContent: 'Start System Call Parsing', + addInfo: { userId: '' }, } ]; @@ -417,6 +530,11 @@ export class FlagsConfig { }); // @ts-ignore parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? 1 : 0; + // @ts-ignore + if (configItem.title === 'System Calls') { + // @ts-ignore + parseConfig[configItem.title] = selectedOption[0].option === 'Enabled' ? FlagsConfig.getSystemcallEventId('SystemParsing').join(';') : ''; + } }); return JSON.stringify({ config: parseConfig }); } @@ -471,6 +589,21 @@ export class FlagsConfig { flagConfigObj[key] = value; window.localStorage.setItem(FlagsConfig.FLAGS_CONFIG_KEY, JSON.stringify(flagConfigObj)); } + + + static getSystemcallEventId(value: string): number[] { + let list = window.localStorage.getItem(FlagsConfig.SYSTEM_PRASE); + return JSON.parse(list!); + } + + static updateSystemcallEventId(systemCallEventId: number[], value: unknown): void { + let systemcallEventId = window.localStorage.getItem(FlagsConfig.SYSTEM_PRASE); + let systemCallEventIdArray:number[] = []; + if (systemcallEventId !== null) { + systemCallEventIdArray = systemCallEventId; + } + window.localStorage.setItem(FlagsConfig.SYSTEM_PRASE, JSON.stringify(systemCallEventIdArray)); + } } export interface FlagConfigItem { @@ -484,3 +617,12 @@ export interface OptionItem { option: string; selected?: boolean; } + +const systemCallConfigList = [ + { + title: 'SystemCall', + des: '', + hidden: true, + type: 'select-multiple', + selectArray: [''], + }] diff --git a/ide/src/trace/component/SpSystemTrace.init.ts b/ide/src/trace/component/SpSystemTrace.init.ts index e239e4f9..8d43e0cd 100644 --- a/ide/src/trace/component/SpSystemTrace.init.ts +++ b/ide/src/trace/component/SpSystemTrace.init.ts @@ -1190,6 +1190,7 @@ async function spSystemTraceInitBuffer( sp: SpSystemTrace, param: { buf?: ArrayBuffer; Url?: string; buf2?: ArrayBuffer }, wasmConfigUri: string, + configUri: string, progress: Function ): Promise<{ status: boolean; @@ -1203,13 +1204,23 @@ async function spSystemTraceInitBuffer( error('getWasmConfigFailed', e); } let parseConfig = FlagsConfig.getSpTraceStreamParseConfig(); - let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, parseConfig, configJson, progress); + let systemParseConfigJson = ''; + try { + systemParseConfigJson = await fetch(configUri).then((res) => res.text()); + let systemParseConfig = JSON.parse(systemParseConfigJson); + let parseConfigObj = JSON.parse(parseConfig); + systemParseConfig.config = parseConfigObj.config; + systemParseConfigJson = JSON.stringify(systemParseConfig); + } catch (e) { + error('systemParseConfigJsonFailed', e); + } + let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, systemParseConfigJson, configJson, progress); if (!status) { return { status: false, msg: msg }; } SpSystemTrace.SDK_CONFIG_MAP = sdkConfigMap; if (param.buf2) { - let { status, msg } = await threadPool2.initSqlite(param.buf2, parseConfig, configJson, progress); + let { status, msg } = await threadPool2.initSqlite(param.buf2, systemParseConfigJson, configJson, progress); if (!status) { return { status: false, msg: msg }; } @@ -1223,6 +1234,7 @@ async function spSystemTraceInitUrl( sp: SpSystemTrace, param: { buf?: ArrayBuffer; url?: string }, wasmConfigUri: string, + configUri: string, progress: Function ): Promise<{ status: boolean; @@ -1243,16 +1255,17 @@ export async function spSystemTraceInit( sp: SpSystemTrace, param: { buf?: ArrayBuffer; url?: string; buf2?: ArrayBuffer; fileName1?: string; fileName2?: string }, wasmConfigUri: string, + configUri: string, progress: Function, isDistributed: boolean ): Promise { progress('Load database', 6); sp.rowsPaneEL!.scroll({ top: 0, left: 0 }); - let rsBuf = await spSystemTraceInitBuffer(sp, param, wasmConfigUri, progress); + let rsBuf = await spSystemTraceInitBuffer(sp, param, wasmConfigUri, configUri, progress); if (rsBuf) { return rsBuf; } - let rsUrl = await spSystemTraceInitUrl(sp, param, wasmConfigUri, progress); + let rsUrl = await spSystemTraceInitUrl(sp, param, wasmConfigUri, configUri, progress); if (rsUrl) { return rsUrl; } diff --git a/ide/src/trace/component/SpSystemTrace.ts b/ide/src/trace/component/SpSystemTrace.ts index 32bcd136..8f1449ea 100644 --- a/ide/src/trace/component/SpSystemTrace.ts +++ b/ide/src/trace/component/SpSystemTrace.ts @@ -2257,7 +2257,7 @@ export class SpSystemTrace extends BaseElement { complete?: ((res: { status: boolean; msg: string }) => void) | undefined ): void { this.observerScrollHeightEnable = false; - this.init({ url: url }, '', progress, false).then((res) => { + this.init({ url: url }, '', '', progress, false).then((res) => { if (complete) { // @ts-ignore complete(res); @@ -2271,6 +2271,7 @@ export class SpSystemTrace extends BaseElement { loadDatabaseArrayBuffer( buf: ArrayBuffer, thirdPartyWasmConfigUrl: string, + configUrl:string, progress: (name: string, percent: number) => void, isDistributed: boolean, complete?: ((res: { status: boolean; msg: string }) => void) | undefined, @@ -2284,7 +2285,7 @@ export class SpSystemTrace extends BaseElement { } else { this.timerShaftEL?.removeAttribute('distributed'); } - this.init({ buf, buf2, fileName1, fileName2 }, thirdPartyWasmConfigUrl, progress, isDistributed).then((res) => { + this.init({ buf, buf2, fileName1, fileName2 }, thirdPartyWasmConfigUrl, configUrl, progress, isDistributed).then((res) => { // @ts-ignore this.rowsEL?.querySelectorAll('trace-row').forEach((it: unknown) => this.observer.observe(it)); if (complete) { @@ -2748,10 +2749,11 @@ export class SpSystemTrace extends BaseElement { init = async ( param: { buf?: ArrayBuffer; url?: string; buf2?: ArrayBuffer; fileName1?: string; fileName2?: string }, wasmConfigUri: string, + configUrl: string, progress: Function, isDistributed: boolean ): Promise => { - return spSystemTraceInit(this, param, wasmConfigUri, progress, isDistributed); + return spSystemTraceInit(this, param, wasmConfigUri, configUrl, progress, isDistributed); }; // @ts-ignore extracted(it: TraceRow) { diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts index ab9af407..f73df505 100644 --- a/ide/src/trace/component/chart/SpProcessChart.ts +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -620,7 +620,9 @@ export class SpProcessChart { processRow.rowType = TraceRow.ROW_TYPE_PROCESS; processRow.rowParentId = ''; processRow.style.height = '40px'; - this.processRowSettingConfig(processRow); + if (FlagsConfig.getFlagsConfigEnableStatus('System Calls')) { + this.processRowSettingConfig(processRow); + } processRow.folder = true; if ( //@ts-ignore diff --git a/ide/src/trace/component/trace/base/SysCallUtils.ts b/ide/src/trace/component/trace/base/SysCallUtils.ts index 3b8609a1..eda34c18 100644 --- a/ide/src/trace/component/trace/base/SysCallUtils.ts +++ b/ide/src/trace/component/trace/base/SysCallUtils.ts @@ -14,282 +14,334 @@ */ export const SysCallMap = new Map([ - [0, "sys_io_setup"], - [1, "sys_io_destroy"], - [2, "sys_io_submit"], - [3, "sys_io_cancel"], - [4, "sys_io_getevents"], - [5, "sys_setxattr"], - [6, "sys_lsetxattr"], - [7, "sys_fsetxattr"], - [8, "sys_getxattr"], - [9, "sys_lgetxattr"], - [10, "sys_fgetxattr"], - [11, "sys_listxattr"], - [12, "sys_llistxattr"], - [13, "sys_flistxattr"], - [14, "sys_removexattr"], - [15, "sys_lremovexattr"], - [16, "sys_fremovexattr"], - [17, "sys_getcwd"], - [18, "sys_lookup_dcookie"], - [19, "sys_eventfd2"], - [20, "sys_epoll_create1"], - [21, "sys_epoll_ctl"], - [22, "sys_epoll_pwait"], - [23, "sys_dup"], - [24, "sys_dup3"], - [25, "sys_fcntl"], - [26, "sys_inotify_init1"], - [27, "sys_inotify_add_watch"], - [28, "sys_inotify_rm_watch"], - [29, "sys_ioctl"], - [30, "sys_ioprio_set"], - [31, "sys_ioprio_get"], - [32, "sys_flock"], - [33, "sys_mknodat"], - [34, "sys_mkdirat"], - [35, "sys_unlinkat"], - [36, "sys_symlinkat"], - [37, "sys_linkat"], - [38, "sys_renameat"], - [39, "sys_umount2"], - [40, "sys_mount"], - [41, "sys_pivot_root"], - [42, "sys_nfsservctl"], - [43, "sys_statfs"], - [44, "sys_fstatfs"], - [45, "sys_truncate"], - [46, "sys_ftruncate"], - [47, "sys_fallocate"], - [48, "sys_faccessat"], - [49, "sys_chdir"], - [50, "sys_fchdir"], - [51, "sys_chroot"], - [52, "sys_fchmod"], - [53, "sys_fchmodat"], - [54, "sys_fchownat"], - [55, "sys_fchown"], - [56, "sys_openat"], - [57, "sys_close"], - [58, "sys_vhangup"], - [59, "sys_pipe2"], - [60, "sys_quotactl"], - [61, "sys_getdents64"], - [62, "sys_lseek"], - [63, "sys_read"], - [64, "sys_write"], - [65, "sys_readlinkat"], - [66, "sys_fstatat"], - [67, "sys_fstat"], - [68, "sys_sync"], - [69, "sys_fsync"], - [70, "sys_fdatasync"], - [71, "sys_sync_file_range"], - [72, "sys_timerfd_create"], - [73, "sys_timerfd_settime"], - [74, "sys_timerfd_gettime"], - [75, "sys_utimensat"], - [76, "sys_acct"], - [77, "sys_capget"], - [78, "sys_capset"], - [79, "sys_personality"], - [93, "sys_exit"], - [94, "sys_exit_group"], - [95, "sys_waitid"], - [96, "sys_set_tid_address"], - [97, "sys_unshare"], - [98, "sys_futex"], - [99, "sys_set_robust_list"], - [100, "sys_get_robust_list"], - [101, "sys_nanosleep"], - [102, "sys_getitimer"], - [103, "sys_setitimer"], - [104, "sys_kexec_load"], - [105, "sys_init_module"], - [106, "sys_delete_module"], - [107, "sys_timer_create"], - [108, "sys_timer_settime"], - [109, "sys_timer_gettime"], - [110, "sys_timer_getoverrun"], - [111, "sys_timer_delete"], - [112, "sys_clock_settime"], - [113, "sys_clock_gettime"], - [114, "sys_clock_getres"], - [115, "sys_clock_nanosleep"], - [116, "sys_syslog"], - [117, "sys_ptrace"], - [118, "sys_sched_setparam"], - [119, "sys_sched_setscheduler"], - [120, "sys_sched_getscheduler"], - [121, "sys_sched_getparam"], - [122, "sys_sched_setaffinity"], - [123, "sys_sched_getaffinity"], - [124, "sys_sched_yield"], - [125, "sys_sched_get_priority_max"], - [126, "sys_sched_get_priority_min"], - [127, "sys_sched_rr_get_interval"], - [128, "sys_restart_syscall"], - [129, "sys_kill"], - [130, "sys_tkill"], - [131, "sys_tgkill"], - [132, "sys_sigaltstack"], - [133, "sys_rt_sigsuspend"], - [134, "sys_rt_sigaction"], - [135, "sys_rt_sigprocmask"], - [136, "sys_rt_sigpending"], - [137, "sys_rt_sigtimedwait"], - [138, "sys_rt_sigqueueinfo"], - [139, "sys_rt_sigreturn"], - [140, "sys_setpriority"], - [141, "sys_getpriority"], - [142, "sys_reboot"], - [143, "sys_setregid"], - [144, "sys_setgid"], - [145, "sys_setreuid"], - [146, "sys_setuid"], - [147, "sys_setresuid"], - [148, "sys_getresuid"], - [149, "sys_setresgid"], - [150, "sys_getresgid"], - [151, "sys_setfsuid"], - [152, "sys_setfsgid"], - [153, "sys_times"], - [154, "sys_setpgid"], - [155, "sys_getpgid"], - [156, "sys_getsid"], - [157, "sys_setsid"], - [158, "sys_getgroups"], - [159, "sys_setgroups"], - [160, "sys_uname"], - [161, "sys_sethostname"], - [162, "sys_setdomainname"], - [163, "sys_getrlimit"], - [164, "sys_setrlimit"], - [165, "sys_getrusage"], - [166, "sys_umask"], - [167, "sys_prctl"], - [168, "sys_getcpu"], - [169, "sys_gettimeofday"], - [170, "sys_settimeofday"], - [171, "sys_adjtimex"], - [172, "sys_getpid"], - [173, "sys_getppid"], - [174, "sys_getuid"], - [175, "sys_geteuid"], - [176, "sys_getgid"], - [177, "sys_getegid"], - [178, "sys_gettid"], - [179, "sys_sysinfo"], - [180, "sys_mq_open"], - [181, "sys_mq_unlink"], - [182, "sys_mq_timedsend"], - [183, "sys_mq_timedreceive"], - [184, "sys_mq_notify"], - [185, "sys_mq_getsetattr"], - [186, "sys_msgget"], - [187, "sys_msgctl"], - [188, "sys_msgrcv"], - [189, "sys_msgsnd"], - [190, "sys_semget"], - [191, "sys_semctl"], - [192, "sys_semop"], - [193, "sys_semtimedop"], - [194, "sys_shmget"], - [195, "sys_shmctl"], - [196, "sys_shmat"], - [197, "sys_shmdt"], - [198, "sys_socket"], - [199, "sys_socketpair"], - [200, "sys_bind"], - [201, "sys_listen"], - [202, "sys_accept"], - [203, "sys_connect"], - [204, "sys_getsockname"], - [205, "sys_getpeername"], - [206, "sys_sendto"], - [207, "sys_recvfrom"], - [208, "sys_setsockopt"], - [209, "sys_getsockopt"], - [210, "sys_shutdown"], - [211, "sys_sendmsg"], - [212, "sys_recvmsg"], - [213, "sys_readahead"], - [214, "sys_brk"], - [215, "sys_munmap"], - [216, "sys_mremap"], - [217, "sys_add_key"], - [218, "sys_request_key"], - [219, "sys_keyctl"], - [220, "sys_clone"], - [221, "sys_execve"], - [222, "sys_mmap"], - [223, "sys_fadvise64"], - [224, "sys_swapon"], - [225, "sys_swapoff"], - [226, "sys_mprotect"], - [227, "sys_msync"], - [228, "sys_mlock"], - [229, "sys_munlock"], - [230, "sys_mlockall"], - [231, "sys_munlockall"], - [232, "sys_mincore"], - [233, "sys_madvise"], - [234, "sys_remap_file_pages"], - [235, "sys_mbind"], - [236, "sys_get_mempolicy"], - [237, "sys_set_mempolicy"], - [238, "sys_migrate_pages"], - [239, "sys_move_pages"], - [240, "sys_rt_tgsigqueueinfo"], - [241, "sys_perf_event_open"], - [242, "sys_accept4"], - [243, "sys_recvmmsg"], - [260, "sys_wait4"], - [261, "sys_prlimit64"], - [262, "sys_fanotify_init"], - [263, "sys_fanotify_mark"], - [264, "sys_name_to_handle_at"], - [265, "sys_open_by_handle_at"], - [266, "sys_clock_adjtime"], - [267, "sys_syncfs"], - [268, "sys_setns"], - [269, "sys_sendmmsg"], - [270, "sys_process_vm_readv"], - [271, "sys_process_vm_writev"], - [272, "sys_kcmp"], - [273, "sys_finit_module"], - [274, "sys_sched_setattr"], - [275, "sys_sched_getattr"], - [276, "sys_renameat2"], - [277, "sys_seccomp"], - [278, "sys_getrandom"], - [279, "sys_memfd_create"], - [280, "sys_bpf"], - [281, "sys_execveat"], - [282, "sys_userfaultfd"], - [283, "sys_membarrier"], - [284, "sys_mlock2"], - [285, "sys_copy_file_range"], - [286, "sys_preadv2"], - [287, "sys_pwritev2"], - [288, "sys_pkey_mprotect"], - [289, "sys_pkey_alloc"], - [290, "sys_pkey_free"], - [291, "sys_statx"], - [292, "sys_io_pgetevents"], - [293, "sys_rseq"], - [294, "sys_kexec_file_load"], - [424, "sys_pidfd_send_signal"], - [425, "sys_io_uring_setup"], - [426, "sys_io_uring_enter"], - [427, "sys_io_uring_register"], - [428, "sys_open_tree"], - [429, "sys_move_mount"], - [430, "sys_fsopen"], - [431, "sys_fsconfig"], - [432, "sys_fsmount"], - [433, "sys_fspick"], - [434, "sys_pidfd_open"], - [435, "sys_clone3"] + [0, "sys_io_setup"], + [1, "sys_io_destroy"], + [2, "sys_io_submit"], + [3, "sys_io_cancel"], + [4, "sys_io_getevents"], + [5, "sys_setxattr"], + [6, "sys_lsetxattr"], + [7, "sys_fsetxattr"], + [8, "sys_getxattr"], + [9, "sys_lgetxattr"], + [10, "sys_fgetxattr"], + [11, "sys_listxattr"], + [12, "sys_llistxattr"], + [13, "sys_flistxattr"], + [14, "sys_removexattr"], + [15, "sys_lremovexattr"], + [16, "sys_fremovexattr"], + [17, "sys_getcwd"], + [18, "sys_lookup_dcookie"], + [19, "sys_eventfd2"], + [20, "sys_epoll_create1"], + [21, "sys_epoll_ctl"], + [22, "sys_epoll_pwait"], + [23, "sys_dup"], + [24, "sys_dup3"], + [25, "sys_fcntl"], + [26, "sys_inotify_init1"], + [27, "sys_inotify_add_watch"], + [28, "sys_inotify_rm_watch"], + [29, "sys_ioctl"], + [30, "sys_ioprio_set"], + [31, "sys_ioprio_get"], + [32, "sys_flock"], + [33, "sys_mknodat"], + [34, "sys_mkdirat"], + [35, "sys_unlinkat"], + [36, "sys_symlinkat"], + [37, "sys_linkat"], + [38, "sys_renameat"], + [39, "sys_umount2"], + [40, "sys_mount"], + [41, "sys_pivot_root"], + [42, "sys_nfsservctl"], + [43, "sys_statfs"], + [44, "sys_fstatfs"], + [45, "sys_truncate"], + [46, "sys_ftruncate"], + [47, "sys_fallocate"], + [48, "sys_faccessat"], + [49, "sys_chdir"], + [50, "sys_fchdir"], + [51, "sys_chroot"], + [52, "sys_fchmod"], + [53, "sys_fchmodat"], + [54, "sys_fchownat"], + [55, "sys_fchown"], + [56, "sys_openat"], + [57, "sys_close"], + [58, "sys_vhangup"], + [59, "sys_pipe2"], + [60, "sys_quotactl"], + [61, "sys_getdents64"], + [62, "sys_lseek"], + [63, "sys_read"], + [64, "sys_write"], + [65, "sys_readv"], + [66, "sys_writev"], + [67, "sys_pread64"], + [68, "sys_pwrite64"], + [69, "sys_preadv"], + [70, "sys_pwritev"], + [71, "sys_sendfile"], + [72, "sys_pselect6"], + [73, "sys_ppoll"], + [74, "sys_signalfd4"], + [75, "sys_vmsplice"], + [76, "sys_splice"], + [77, "sys_tee"], + [78, "sys_readlinkat"], + [79, "sys_fstatat"], + [80, "sys_fstat"], + [81, "sys_sync"], + [82, "sys_fsync"], + [83, "sys_fdatasync"], + [84, "sys_sync_file_range"], + [85, "sys_timerfd_create"], + [86, "sys_timerfd_settime"], + [87, "sys_timerfd_gettime"], + [88, "sys_utimensat"], + [89, "sys_acct"], + [90, "sys_capget"], + [91, "sys_capset"], + [92, "sys_personality"], + [93, "sys_exit"], + [94, "sys_exit_group"], + [95, "sys_waitid"], + [96, "sys_set_tid_address"], + [97, "sys_unshare"], + [98, "sys_futex"], + [99, "sys_set_robust_list"], + [100, "sys_get_robust_list"], + [101, "sys_nanosleep"], + [102, "sys_getitimer"], + [103, "sys_setitimer"], + [104, "sys_kexec_load"], + [105, "sys_init_module"], + [106, "sys_delete_module"], + [107, "sys_timer_create"], + [108, "sys_timer_gettime"], + [109, "sys_timer_getoverrun"], + [110, "sys_timer_settime"], + [111, "sys_timer_delete"], + [112, "sys_clock_settime"], + [113, "sys_clock_gettime"], + [114, "sys_clock_getres"], + [115, "sys_clock_nanosleep"], + [116, "sys_syslog"], + [117, "sys_ptrace"], + [118, "sys_sched_setparam"], + [119, "sys_sched_setscheduler"], + [120, "sys_sched_getscheduler"], + [121, "sys_sched_getparam"], + [122, "sys_sched_setaffinity"], + [123, "sys_sched_getaffinity"], + [124, "sys_sched_yield"], + [125, "sys_sched_get_priority_max"], + [126, "sys_sched_get_priority_min"], + [127, "sys_sched_rr_get_interval"], + [128, "sys_restart_syscall"], + [129, "sys_kill"], + [130, "sys_tkill"], + [131, "sys_tgkill"], + [132, "sys_sigaltstack"], + [133, "sys_rt_sigsuspend"], + [134, "sys_rt_sigaction"], + [135, "sys_rt_sigprocmask"], + [136, "sys_rt_sigpending"], + [137, "sys_rt_sigtimedwait"], + [138, "sys_rt_sigqueueinfo"], + [139, "sys_rt_sigreturn"], + [140, "sys_setpriority"], + [141, "sys_getpriority"], + [142, "sys_reboot"], + [143, "sys_setregid"], + [144, "sys_setgid"], + [145, "sys_setreuid"], + [146, "sys_setuid"], + [147, "sys_setresuid"], + [148, "sys_getresuid"], + [149, "sys_setresgid"], + [150, "sys_getresgid"], + [151, "sys_setfsuid"], + [152, "sys_setfsgid"], + [153, "sys_times"], + [154, "sys_setpgid"], + [155, "sys_getpgid"], + [156, "sys_getsid"], + [157, "sys_setsid"], + [158, "sys_getgroups"], + [159, "sys_setgroups"], + [160, "sys_uname"], + [161, "sys_sethostname"], + [162, "sys_setdomainname"], + [163, "sys_getrlimit"], + [164, "sys_setrlimit"], + [165, "sys_getrusage"], + [166, "sys_umask"], + [167, "sys_prctl"], + [168, "sys_getcpu"], + [169, "sys_gettimeofday"], + [170, "sys_settimeofday"], + [171, "sys_adjtimex"], + [172, "sys_getpid"], + [173, "sys_getppid"], + [174, "sys_getuid"], + [175, "sys_geteuid"], + [176, "sys_getgid"], + [177, "sys_getegid"], + [178, "sys_gettid"], + [179, "sys_sysinfo"], + [180, "sys_mq_open"], + [181, "sys_mq_unlink"], + [182, "sys_mq_timedsend"], + [183, "sys_mq_timedreceive"], + [184, "sys_mq_notify"], + [185, "sys_mq_getsetattr"], + [186, "sys_msgget"], + [187, "sys_msgctl"], + [188, "sys_msgrcv"], + [189, "sys_msgsnd"], + [190, "sys_semget"], + [191, "sys_semctl"], + [192, "sys_semtimedop"], + [193, "sys_semop"], + [194, "sys_shmget"], + [195, "sys_shmctl"], + [196, "sys_shmat"], + [197, "sys_shmdt"], + [198, "sys_socket"], + [199, "sys_socketpair"], + [200, "sys_bind"], + [201, "sys_listen"], + [202, "sys_accept"], + [203, "sys_connect"], + [204, "sys_getsockname"], + [205, "sys_getpeername"], + [206, "sys_sendto"], + [207, "sys_recvfrom"], + [208, "sys_setsockopt"], + [209, "sys_getsockopt"], + [210, "sys_shutdown"], + [211, "sys_sendmsg"], + [212, "sys_recvmsg"], + [213, "sys_readahead"], + [214, "sys_brk"], + [215, "sys_munmap"], + [216, "sys_mremap"], + [217, "sys_add_key"], + [218, "sys_request_key"], + [219, "sys_keyctl"], + [220, "sys_clone"], + [221, "sys_execve"], + [222, "sys_mmap"], + [223, "sys_fadvise64"], + [224, "sys_swapon"], + [225, "sys_swapoff"], + [226, "sys_mprotect"], + [227, "sys_msync"], + [228, "sys_mlock"], + [229, "sys_munlock"], + [230, "sys_mlockall"], + [231, "sys_munlockall"], + [232, "sys_mincore"], + [233, "sys_madvise"], + [234, "sys_remap_file_pages"], + [235, "sys_mbind"], + [236, "sys_get_mempolicy"], + [237, "sys_set_mempolicy"], + [238, "sys_migrate_pages"], + [239, "sys_move_pages"], + [240, "sys_rt_tgsigqueueinfo"], + [241, "sys_perf_event_open"], + [242, "sys_accept4"], + [243, "sys_recvmmsg"], + [244, "sys_arch_specific_syscall"], + [260, "sys_wait4"], + [261, "sys_prlimit64"], + [262, "sys_fanotify_init"], + [263, "sys_fanotify_mark"], + [264, "sys_name_to_handle_at"], + [265, "sys_open_by_handle_at"], + [266, "sys_clock_adjtime"], + [267, "sys_syncfs"], + [268, "sys_setns"], + [269, "sys_sendmmsg"], + [270, "sys_process_vm_readv"], + [271, "sys_process_vm_writev"], + [272, "sys_kcmp"], + [273, "sys_finit_module"], + [274, "sys_sched_setattr"], + [275, "sys_sched_getattr"], + [276, "sys_renameat2"], + [277, "sys_seccomp"], + [278, "sys_getrandom"], + [279, "sys_memfd_create"], + [280, "sys_bpf"], + [281, "sys_execveat"], + [282, "sys_userfaultfd"], + [283, "sys_membarrier"], + [284, "sys_mlock2"], + [285, "sys_copy_file_range"], + [286, "sys_preadv2"], + [287, "sys_pwritev2"], + [288, "sys_pkey_mprotect"], + [289, "sys_pkey_alloc"], + [290, "sys_pkey_free"], + [291, "sys_statx"], + [292, "sys_io_pgetevents"], + [293, "sys_rseq"], + [294, "sys_kexec_file_load"], + [403, "sys_clock_gettime64"], + [404, "sys_clock_settime64"], + [405, "sys_clock_adjtime64"], + [406, "sys_clock_getres_time64"], + [407, "sys_clock_nanosleep_time64"], + [408, "sys_timer_gettime64"], + [409, "sys_timer_settime64"], + [410, "sys_timerfd_gettime64"], + [411, "sys_timerfd_settime64"], + [412, "sys_utimensat_time64"], + [413, "sys_pselect6_time64"], + [414, "sys_ppoll_time64"], + [416, "sys_io_pgetevents_time64"], + [417, "sys_recvmmsg_time64"], + [418, "sys_mq_timedsend_time64"], + [419, "sys_mq_timedreceive_time64"], + [420, "sys_semtimedop_time64"], + [421, "sys_rt_sigtimedwait_time64"], + [422, "sys_futex_time64"], + [423, "sys_sched_rr_get_interval_time64"], + [424, "sys_pidfd_send_signal"], + [425, "sys_io_uring_setup"], + [426, "sys_io_uring_enter"], + [427, "sys_io_uring_register"], + [428, "sys_open_tree"], + [429, "sys_move_mount"], + [430, "sys_fsopen"], + [431, "sys_fsconfig"], + [432, "sys_fsmount"], + [433, "sys_fspick"], + [434, "sys_pidfd_open"], + [435, "sys_clone3"], + [436, "sys_close_range"], + [437, "sys_openat2"], + [438, "sys_pidfd_getfd"], + [439, "sys_faccessat2"], + [440, "sys_process_madvise"], + [441, "sys_epoll_pwait2"], + [442, "sys_mount_setattr"], + [443, "sys_quotactl_fd"], + [444, "sys_landlock_create_ruleset"], + [445, "sys_landlock_add_rule"], + [446, "sys_landlock_restrict_self"], + [447, "sys_memfd_secret"], + [448, "sys_process_mrelease"], + [449, "sys_futex_waitv"], + [450, "sys_set_mempolicy_home_node"], + [451, "sys_cachestat"], + [452, "sys_fchmodat2"], + [453, "sys_syscalls"] ]); \ No newline at end of file diff --git a/ide/src/trace/database/TraceWorker.ts b/ide/src/trace/database/TraceWorker.ts index 1923ed8a..b9bb33ee 100644 --- a/ide/src/trace/database/TraceWorker.ts +++ b/ide/src/trace/database/TraceWorker.ts @@ -332,7 +332,7 @@ function parseThirdWasmByOpenAction(e: MessageEvent): void { if (parseConfig !== '') { let parseConfigArray = enc.encode(parseConfig); //@ts-ignore - let parseConfigAddr = wasmModule._InitializeParseConfig(1024); + let parseConfigAddr = wasmModule._InitializeParseConfig(parseConfigArray.length); //@ts-ignore wasmModule.HEAPU8.set(parseConfigArray, parseConfigAddr); //@ts-ignore diff --git a/ide/src/trace/database/data-trafic/process/ThreadSysCallDataReceiver.ts b/ide/src/trace/database/data-trafic/process/ThreadSysCallDataReceiver.ts index 61af08b9..8001f4c0 100644 --- a/ide/src/trace/database/data-trafic/process/ThreadSysCallDataReceiver.ts +++ b/ide/src/trace/database/data-trafic/process/ThreadSysCallDataReceiver.ts @@ -12,22 +12,46 @@ // limitations under the License. import { Args } from '../CommonArgs'; +import { threadSysCallList } from '../utils/AllMemoryCache'; +import { filterDataByGroup } from '../utils/DataFilter'; import { TraficEnum } from '../utils/QueryEnum'; export const chartThreadSysCallDataSql = (args: Args):unknown => { - return `SELECT syscall_number as id, itid, ts - ${args.recordStartNS} as startTs, dur + return `SELECT syscall_number as id, itid, ts - ${args.recordStartNS} as startTs, max(dur) as dur, + ((ts - ${args.recordStartNS}) / (${Math.floor((args.endNS - args.startNS) / args.width)})) AS px from syscall where itid = ${args.itid} and startTs + dur >= ${Math.floor(args.startNS)} and startTs <= ${Math.floor(args.endNS)} + group by px `; }; +export const sysCallMemSql = (args: Args): unknown => { + return `select syscall_number as id, (ts - ${args.recordStartNS}) as startTs, dur from syscall where itid = ${args.itid}` +} + export function threadSysCallDataReceiver(data: unknown, proc: Function): void { //@ts-ignore - let sql = chartThreadSysCallDataSql(data.params); - let res = proc(sql); //@ts-ignore - arrayBufferHandler(data, res, data.params.trafic !== TraficEnum.SharedArrayBuffer, false); + let itid: number = data.params.itid; + let arr: unknown[] = []; + if (threadSysCallList.has(itid)) { + arr = threadSysCallList.get(itid) || []; + } else { + //@ts-ignore + let sql = sysCallMemSql(data.params); + arr = proc(sql); //@ts-ignore + threadSysCallList.set(itid, arr); + } + let res = filterDataByGroup( + arr, + 'startTs', + 'dur', //@ts-ignore + data.params.startNS, //@ts-ignore + data.params.endNS, //@ts-ignore + data.params.width + ); + arrayBufferHandler(data, res, true, false); } function arrayBufferHandler(data: unknown, res: unknown[], transfer: boolean, isEmpty: boolean): void { @@ -42,7 +66,7 @@ function arrayBufferHandler(data: unknown, res: unknown[], transfer: boolean, is startTs[i] = it.startTs; //@ts-ignore dur[i] = it.dur; //@ts-ignore id[i] = it.id; //@ts-ignore - itid[i] = it.itid; //@ts-ignore + itid[i] = data.params.itid; //@ts-ignore }); (self as unknown as Worker).postMessage( { diff --git a/ide/src/trace/database/data-trafic/process/ThreadSysCallDataSender.ts b/ide/src/trace/database/data-trafic/process/ThreadSysCallDataSender.ts index 2e296f12..f874b4f4 100644 --- a/ide/src/trace/database/data-trafic/process/ThreadSysCallDataSender.ts +++ b/ide/src/trace/database/data-trafic/process/ThreadSysCallDataSender.ts @@ -73,7 +73,7 @@ function arrayBufferHandler(buffers: unknown, len: number, tid: number, pid: num dur: dur[i], id: id[i], itid: itid[i], - name: SysCallMap.get(id[i]), + name: SysCallMap.get(id[i]) || 'unknown event', tid: tid, pid: pid, } as ThreadSysCallStruct); diff --git a/ide/src/trace/database/data-trafic/utils/AllMemoryCache.ts b/ide/src/trace/database/data-trafic/utils/AllMemoryCache.ts index d73f3e6f..3abdb0f6 100644 --- a/ide/src/trace/database/data-trafic/utils/AllMemoryCache.ts +++ b/ide/src/trace/database/data-trafic/utils/AllMemoryCache.ts @@ -47,6 +47,8 @@ export const processList: Map> = new Map(); export const memList: Map> = new Map(); //线程状态 泳道图 memory 模式缓存 export const threadStateList: Map> = new Map(); +//线程系统调用 泳道图 memory数据缓存 +export const threadSysCallList: Map> = new Map(); //进程下卡顿丢帧 泳道图 memory 模式缓存 export const processFrameList: Map> = new Map(); //hiSysEvent 泳道图 memory 模式缓存 @@ -78,6 +80,7 @@ export function clearMemoryCache(data: unknown, proc: Function): void { processList.clear(); memList.clear(); threadStateList.clear(); + threadSysCallList.clear(); processFrameList.clear(); lostFrameList.clear(); hitchTimeList.clear(); diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerThreadSysCall.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerThreadSysCall.ts index aac9df64..823fe4f2 100644 --- a/ide/src/trace/database/ui-worker/ProcedureWorkerThreadSysCall.ts +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerThreadSysCall.ts @@ -107,7 +107,7 @@ export class ThreadSysCallStruct extends BaseStruct { threadContext.fillStyle = ColorUtils.funcTextColor(textColor); threadContext.textBaseline = 'middle'; threadContext.font = '8px sans-serif'; - data.frame.width > 7 && drawString(threadContext, data.name!, 2, data.frame, data); + data.frame.width > 7 && data.name && drawString(threadContext, data.name, 2, data.frame, data); if ( ThreadSysCallStruct.selectStruct && ThreadSysCallStruct.equals(ThreadSysCallStruct.selectStruct, data) diff --git a/ide/webpack.config.js b/ide/webpack.config.js index 598d3265..4ff1db13 100644 --- a/ide/webpack.config.js +++ b/ide/webpack.config.js @@ -147,6 +147,10 @@ const config = { from: './src/doc', to: 'doc', }, + { + from: './src/config', + to: 'config', + }, { from: './src/base-ui/icon.svg', to: 'base-ui/icon.svg', -- Gitee From 4277877b5ea4e99971edf101207296df9fefa87b Mon Sep 17 00:00:00 2001 From: JustinYT Date: Tue, 20 May 2025 09:47:42 +0800 Subject: [PATCH 17/51] update compile script for bzip2. Signed-off-by: JustinYT --- trace_streamer/pare_third_party.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/trace_streamer/pare_third_party.sh b/trace_streamer/pare_third_party.sh index a0b7cfa8..a3d03073 100755 --- a/trace_streamer/pare_third_party.sh +++ b/trace_streamer/pare_third_party.sh @@ -57,9 +57,6 @@ fi if [ ! -f "bzip2/BUILD.gn" ];then git clone --depth=1 git@gitee.com:openharmony/third_party_bzip2.git bzip2 - cd bzip2 - ./install.sh $(pwd) - cd .. fi if [ ! -f "googletest/BUILD.gn" ];then -- Gitee From 1dd0024168dbb4f00183ccd5ae6df3f3b8cf5e18 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Wed, 21 May 2025 11:09:31 +0800 Subject: [PATCH 18/51] fix config.json not find Signed-off-by: JustinYT --- ide/src/trace/component/SpSystemTrace.init.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ide/src/trace/component/SpSystemTrace.init.ts b/ide/src/trace/component/SpSystemTrace.init.ts index 8d43e0cd..75b7b3ea 100644 --- a/ide/src/trace/component/SpSystemTrace.init.ts +++ b/ide/src/trace/component/SpSystemTrace.init.ts @@ -1212,6 +1212,7 @@ async function spSystemTraceInitBuffer( systemParseConfig.config = parseConfigObj.config; systemParseConfigJson = JSON.stringify(systemParseConfig); } catch (e) { + systemParseConfigJson = parseConfig; error('systemParseConfigJsonFailed', e); } let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, systemParseConfigJson, configJson, progress); -- Gitee From e77dbc37075a7606335e3177a7ab2c5deb1b6f31 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Wed, 21 May 2025 11:19:01 +0800 Subject: [PATCH 19/51] adjust syscalls json for use value Signed-off-by: JustinYT --- trace_streamer/src/filter/config_filter.cpp | 4 ++-- trace_streamer/src/rpc/rpc_server.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/trace_streamer/src/filter/config_filter.cpp b/trace_streamer/src/filter/config_filter.cpp index d184bb8f..dd03a20c 100644 --- a/trace_streamer/src/filter/config_filter.cpp +++ b/trace_streamer/src/filter/config_filter.cpp @@ -42,7 +42,7 @@ ConfigFilter::ConfigFilter(TraceDataCache *dataCache, const TraceStreamerFilters ConfigFilter::~ConfigFilter() {} bool ConfigFilter::SetConfig(const std::string &configFile) { - json configResult = json::parse(configFile); + json configResult = json::parse(configFile, nullptr, false); if (configResult.is_discarded()) { TS_LOGE("Failed to parse config file."); return false; @@ -154,7 +154,7 @@ SwitchConfig::SwitchConfig(const json &config) HMKernelTraceEnabled_ = config.value("HMKernel", 0) == 1; rawTraceCutStartTsEnabled_ = config.value("RawTraceCutStartTs", 0) == 1; ffrtConvertEnabled_ = config.value("FFRTConvert", 0) == 1; - std::string syscalls = config.at("System Calls"); + std::string syscalls = config.value("System Calls", ""); UpdateSyscallsTsSet(syscalls); TS_LOGI( "appConfigEnabled_=%d, animationConfigEnabled_=%d, taskPoolConfigEnabled_=%d, binderRunnableConfigEnabled_=%d, " diff --git a/trace_streamer/src/rpc/rpc_server.cpp b/trace_streamer/src/rpc/rpc_server.cpp index 39dc4f49..7adcc8a4 100644 --- a/trace_streamer/src/rpc/rpc_server.cpp +++ b/trace_streamer/src/rpc/rpc_server.cpp @@ -837,8 +837,7 @@ bool RpcServer::SplitFile(std::string timeSnaps) bool RpcServer::ParserConfig(std::string parserConfigJson) { - json jMessage = json::parse(parserConfigJson); - jsonns::ParserConfig parserConfig = jMessage.at("config"); + TS_LOGI("parserConfigJson=%s", parserConfigJson.c_str()); ts_->SetConfigFile(parserConfigJson); ffrtConvertEnabled_ = ts_->GetFfrtConfig(); startParseTime_ = -- Gitee From e1c5491833e2cdd8fd0cc1bc5eb9c83c1ffaf02f Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 23 May 2025 14:30:46 +0800 Subject: [PATCH 20/51] =?UTF-8?q?fix:=E6=B1=87=E7=BC=96=E6=89=93=E7=82=B9?= =?UTF-8?q?=E4=B8=8A=E6=8A=A5=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- .../component/trace/sheet/hiperf/TabPanePerfAnalysis.ts | 5 ----- ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index 9b10f55a..c04d2ce9 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -27,7 +27,6 @@ import { TabpanePerfProfile } from './TabPerfProfile'; import { TabPanePerfAnalysisHtml } from './TabPanePerfAnalysis.html'; import { WebSocketManager } from '../../../../../webSocket/WebSocketManager'; import { Constants, TypeConstants } from '../../../../../webSocket/Constants'; -import { SpStatisticsHttpUtil } from '../../../../../statistics/util/SpStatisticsHttpUtil'; @element('tabpane-perf-analysis') export class TabPanePerfAnalysis extends BaseElement { @@ -592,10 +591,6 @@ export class TabPanePerfAnalysis extends BaseElement { } private functionClickEvent(it: unknown) { - SpStatisticsHttpUtil.addOrdinaryVisitAction({ - event: 'hiperf_func', - action: 'hiperf_func', - }); // @ts-ignore this.perfAnalysisHeadTips?.innerHTML = ''; if (this.selectedTabfileName.indexOf('.an') === -1 && this.selectedTabfileName.indexOf('.so') === -1) { diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts index b0db75e2..67d55a23 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.ts @@ -22,6 +22,7 @@ import { } from '../../../../bean/PerfAnalysis'; import { WebSocketManager } from '../../../../../webSocket/WebSocketManager'; import { Constants, TypeConstants } from '../../../../../webSocket/Constants'; +import { SpStatisticsHttpUtil } from '../../../../../statistics/util/SpStatisticsHttpUtil'; @element('tab-perf-func-asm') export class TabPerfFuncAsm extends BaseElement { @@ -170,6 +171,10 @@ export class TabPerfFuncAsm extends BaseElement { if (cmd === Constants.DISASSEMBLY_QUERY_BACK_CMD) { const result = JSON.parse(new TextDecoder().decode(e)); if (result.resultCode === 0) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'hiperf_func', + action: 'hiperf_func', + }); if (result.anFileOff) { this.textFileOffElement!.innerHTML = `.text section: ${result.anFileOff}`; this.textFileOffElement!.style.display = 'block'; -- Gitee From 41ec4561c80157cf088ff5e0603bd414e0fc74f4 Mon Sep 17 00:00:00 2001 From: zhangzhuozhou Date: Thu, 29 May 2025 10:37:50 +0800 Subject: [PATCH 21/51] =?UTF-8?q?feat:=E9=80=82=E9=85=8DH:Marsh=E6=89=93?= =?UTF-8?q?=E7=82=B9=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhuozhou --- .../src/parser/print_event_parser.cpp | 26 +++++++++---------- .../src/parser/print_event_parser.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/trace_streamer/src/parser/print_event_parser.cpp b/trace_streamer/src/parser/print_event_parser.cpp index a7271814..43d0d506 100644 --- a/trace_streamer/src/parser/print_event_parser.cpp +++ b/trace_streamer/src/parser/print_event_parser.cpp @@ -375,21 +375,10 @@ bool PrintEventParser::OnRwTransaction(size_t callStackRow, std::string &args, c { // H:MarshRSTransactionData cmdCount:20 transactionFlag:[3799,8] isUni:1 std::smatch match; - if (std::regex_search(args, match, transFlagPattern_)) { - std::string mainTheadId = match.str(1); - std::string flag2 = match.str(2); - // use to update dstRenderSlice_ - auto mainThreadId = - streamFilters_->processFilter_->GetInternalTid(base::StrToInt(mainTheadId).value()); - // use to update vsyncRenderSlice_ - auto currentThreadId = streamFilters_->processFilter_->GetInternalTid(line.pid); - return streamFilters_->frameFilter_->BeginRSTransactionData( - currentThreadId, base::StrToInt(flag2).value(), mainThreadId); - } if (std::regex_search(args, match, newTransFlagPattern_)) { std::string mainTheadId = match.str(1); - std::string currentThread = match.str(2); - std::string flag2 = match.str(3); + std::string flag2 = match.str(2); + std::string currentThread = match.str(3); std::string timeFlag = match.str(4); auto mainThreadId = streamFilters_->processFilter_->GetInternalTid(base::StrToInt(mainTheadId).value()); @@ -399,6 +388,17 @@ bool PrintEventParser::OnRwTransaction(size_t callStackRow, std::string &args, c return streamFilters_->frameFilter_->BeginRSTransactionData( currentThreadId, base::StrToInt(flag2).value(), mainThreadId, timeId); } + if (std::regex_search(args, match, transFlagPattern_)) { + std::string mainTheadId = match.str(1); + std::string flag2 = match.str(2); + // use to update dstRenderSlice_ + auto mainThreadId = + streamFilters_->processFilter_->GetInternalTid(base::StrToInt(mainTheadId).value()); + // use to update vsyncRenderSlice_ + auto currentThreadId = streamFilters_->processFilter_->GetInternalTid(line.pid); + return streamFilters_->frameFilter_->BeginRSTransactionData( + currentThreadId, base::StrToInt(flag2).value(), mainThreadId); + } return true; } bool PrintEventParser::OnMainThreadProcessCmd(size_t callStackRow, std::string &args, const BytraceLine &line) diff --git a/trace_streamer/src/parser/print_event_parser.h b/trace_streamer/src/parser/print_event_parser.h index 2a6aab55..d3d80a1f 100644 --- a/trace_streamer/src/parser/print_event_parser.h +++ b/trace_streamer/src/parser/print_event_parser.h @@ -100,7 +100,7 @@ private: const std::regex uiVsyncTaskPattern_ = std::regex("\\[(\\w+):(\\d+)\\]"); const std::regex transFlagPattern_ = std::regex(R"(transactionFlag:\[(\d+),(\d+)\])"); const std::regex newTransFlagPattern_ = - std::regex(R"(transactionFlag:\[(\d+),\s*(\d+),\s*(\d+)\],\s*timestamp:(\d+))"); + std::regex(R"(transactionFlag:\[(\d+),(\d+)\],\s*tid:(\d+),\s*timestamp:(\d+))"); const std::regex mainProcessCmdPattern_ = std::regex("\\[(\\d+),(\\d+)\\]"); const std::regex distributeMatcher_ = std::regex(R"(H:\[([a-z0-9]+),([a-z0-9]+),([a-z0-9]+)\]#([CS]?)##(.*))"); std::vector frameCallIds_ = {}; -- Gitee From 914ee178f803f8964412087a5a2289f988b561b1 Mon Sep 17 00:00:00 2001 From: zhangzhuozhou Date: Thu, 29 May 2025 10:41:23 +0800 Subject: [PATCH 22/51] =?UTF-8?q?feat:=E9=80=82=E9=85=8Draw=20trace?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8F=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhuozhou --- .../rawtrace_parser/ftrace_event_processor.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp b/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp index 5e83ac8c..1c8e1678 100644 --- a/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp +++ b/trace_streamer/src/parser/rawtrace_parser/ftrace_event_processor.cpp @@ -299,11 +299,12 @@ bool FtraceEventProcessor::SchedWakeup(FtraceEvent &ftraceEvent, uint8_t data[], schedWakeupMsg->set_pid(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); if (format.fields[index].size == NEW_SCHED_PRIO_SIZE) { schedWakeupMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakeupMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } else { schedWakeupMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakeupMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakeupMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } - schedWakeupMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); - schedWakeupMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); return true; } bool FtraceEventProcessor::SchedWaking(FtraceEvent &ftraceEvent, uint8_t data[], size_t size, const EventFormat &format) @@ -314,11 +315,12 @@ bool FtraceEventProcessor::SchedWaking(FtraceEvent &ftraceEvent, uint8_t data[], schedWakingMsg->set_pid(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); if (format.fields[index].size == NEW_SCHED_PRIO_SIZE) { schedWakingMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakingMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } else { schedWakingMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakingMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + schedWakingMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } - schedWakingMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); - schedWakingMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); return true; } bool FtraceEventProcessor::SchedWakeupNew(FtraceEvent &ftraceEvent, @@ -332,11 +334,12 @@ bool FtraceEventProcessor::SchedWakeupNew(FtraceEvent &ftraceEvent, wakeupNewMsg->set_pid(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); if (format.fields[index].size == NEW_SCHED_PRIO_SIZE) { wakeupNewMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + wakeupNewMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } else { wakeupNewMsg->set_prio(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + wakeupNewMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); + wakeupNewMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); } - wakeupNewMsg->set_success(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); - wakeupNewMsg->set_target_cpu(FtraceFieldProcessor::HandleIntField(format.fields, index++, data, size)); return true; } bool FtraceEventProcessor::SchedProcessExit(FtraceEvent &ftraceEvent, -- Gitee From f1885ecac20ee829881f927d0c7528b9fa64dfd9 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Thu, 29 May 2025 17:23:14 +0800 Subject: [PATCH 23/51] fix hiviewdfx_faultloggerd build. Signed-off-by: JustinYT --- .../patch_hiperf/hiviewdfx_faultloggerd.patch | 76 +++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch index 088df2a3..42e2c46b 100644 --- a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch +++ b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch @@ -1,5 +1,21 @@ +diff --git a/common/dfxutil/dfx_util.cpp b/common/dfxutil/dfx_util.cpp +index a90f4303..9429fd43 100644 +--- a/common/dfxutil/dfx_util.cpp ++++ b/common/dfxutil/dfx_util.cpp +@@ -229,7 +229,11 @@ bool ReadFdToString(int fd, std::string& content) + void CloseFd(int &fd) + { + if (fd > 0) { ++#if is_ohos + fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN)); ++#else ++ close(fd); ++#endif + fd = -1; + } + } diff --git a/common/dfxutil/string_view_util.h b/common/dfxutil/string_view_util.h -index b44a59ea775b368b93391ce19b440f617c309477..7dbd3568df9035edea91e920bf12fa5c58fe116f 100644 +index b44a59ea..7dbd3568 100644 --- a/common/dfxutil/string_view_util.h +++ b/common/dfxutil/string_view_util.h @@ -24,6 +24,24 @@ @@ -106,7 +122,7 @@ index b44a59ea775b368b93391ce19b440f617c309477..7dbd3568df9035edea91e920bf12fa5c } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/common/byte_order.h b/interfaces/common/byte_order.h -index 3c40993ec56288deec6e40420a97d182587e9b62..a55d9db076a6fe1476a52a102fb968adb08073d7 100644 +index 3c40993e..a55d9db0 100644 --- a/interfaces/common/byte_order.h +++ b/interfaces/common/byte_order.h @@ -16,7 +16,7 @@ @@ -119,7 +135,7 @@ index 3c40993ec56288deec6e40420a97d182587e9b62..a55d9db076a6fe1476a52a102fb968ad #define UNWIND_BIG_ENDIAN 4321 #define UNWIND_BYTE_ORDER -1 // Unknown diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_define.h b/interfaces/innerkits/unwinder/include/dfx_elf_define.h -index 6bc9394912c193417cbfe588551b07c255fce62a..a71d76b5641ec347f014736173137cf1115c446b 100644 +index 6bc93949..a71d76b5 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_define.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_define.h @@ -17,7 +17,7 @@ @@ -132,7 +148,7 @@ index 6bc9394912c193417cbfe588551b07c255fce62a..a71d76b5641ec347f014736173137cf1 #include #endif diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h -index b4c84437735176d28f7756930a8027152fc08155..86a4bdd197918e6246edf683eec2d213b1414803 100644 +index b4c84437..86a4bdd1 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h @@ -16,7 +16,7 @@ @@ -145,7 +161,7 @@ index b4c84437735176d28f7756930a8027152fc08155..86a4bdd197918e6246edf683eec2d213 #else #include diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp -index 9398e59acea6722bb1bfebcd0f312ee826a6f5a1..d071f2b934610fb15a921972a9eb97f3c646506f 100644 +index 9398e59a..d071f2b9 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp +++ b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp @@ -20,7 +20,7 @@ @@ -157,3 +173,53 @@ index 9398e59acea6722bb1bfebcd0f312ee826a6f5a1..d071f2b934610fb15a921972a9eb97f3 #include "dfx_nonlinux_define.h" #else #include +diff --git a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp +index cbe67062..52ced531 100644 +--- a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp ++++ b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp +@@ -151,8 +151,10 @@ std::shared_ptr RegularElfFactory::Create() + DFXLOGE("Failed to open file: %{public}s, errno(%{public}d)", filePath_.c_str(), errno); + return regularElf; + } ++#if is_ohos + uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN); + fdsan_exchange_owner_tag(fd, 0, ownerTag); ++#endif + do { + auto size = static_cast(GetFileSize(fd)); + auto mMap = std::make_shared(); +@@ -162,7 +164,11 @@ std::shared_ptr RegularElfFactory::Create() + } + regularElf->SetMmap(mMap); + } while (false); ++#if is_ohos + fdsan_close_with_tag(fd, ownerTag); ++#else ++ close(fd); ++#endif + return regularElf; + } + +@@ -215,8 +221,10 @@ std::shared_ptr CompressHapElfFactory::Create() + DFXLOGE("Failed to open hap file, errno(%{public}d)", errno); + return nullptr; + } ++#if is_ohos + uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN); + fdsan_exchange_owner_tag(fd, 0, ownerTag); ++#endif + std::shared_ptr compressHapElf = nullptr; + do { + size_t elfSize = 0; +@@ -237,7 +245,11 @@ std::shared_ptr CompressHapElfFactory::Create() + break; + } + } while (false); ++#if is_ohos + fdsan_close_with_tag(fd, ownerTag); ++#else ++ close(fd); ++#endif + return compressHapElf; + } + -- Gitee From c25f27c3a9e665a5fbdbd19011dda43e0f7523c4 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Thu, 29 May 2025 20:01:43 +0800 Subject: [PATCH 24/51] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=E5=BF=AB=E7=85=A7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- ide/src/trace/component/chart/SpChartManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ide/src/trace/component/chart/SpChartManager.ts b/ide/src/trace/component/chart/SpChartManager.ts index 3590d966..816d1fe3 100644 --- a/ide/src/trace/component/chart/SpChartManager.ts +++ b/ide/src/trace/component/chart/SpChartManager.ts @@ -62,7 +62,7 @@ import { SpUserFileChart } from './SpUserPluginChart'; import { SpImportUserPluginsChart } from './SpImportUserPluginsChart'; import { queryDmaFenceIdAndCat } from '../../database/sql/dmaFence.sql'; import { queryAllFuncNames } from '../../database/sql/Func.sql'; -import {SpSnapShotChart} from './spSnapShotChart'; +import { SpSnapShotChart } from './spSnapShotChart'; import { SpRecordTrace } from '../SpRecordTrace'; export class SpChartManager { @@ -197,7 +197,7 @@ export class SpChartManager { await this.initCpu(progress); await this.logChart.init(); await this.spHiSysEvent.init(); - if (SpRecordTrace.snapShotList.length > 0) { + if (SpRecordTrace.snapShotList.length > 0 && SpRecordTrace.isSnapShotCapture) { await this.spSnapShotChart.init(); } let idAndNameArr = await queryDmaFenceIdAndCat(); -- Gitee From d77ebda4efd37315a6cc07b2878c5b4ebe647639 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 30 May 2025 10:21:29 +0800 Subject: [PATCH 25/51] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E9=9A=94=E5=A4=A9?= =?UTF-8?q?=E5=AF=BC=E5=85=A5trace=E8=A3=81=E5=89=AA=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- ide/src/trace/SpApplication.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index dd3c76b9..4ec46ec8 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -182,6 +182,7 @@ export class SpApplication extends BaseElement { static traceType: String = ''; private isZipFile: boolean = false; isClear: boolean = false; + isOpenTrace: boolean = false; static spSnapShotView: SpSnapShotView | undefined | null; static get observedAttributes(): Array { @@ -649,6 +650,7 @@ export class SpApplication extends BaseElement { private openTraceFile(ev: File): void { SpApplication.isTraceLoaded = false; + this.isOpenTrace = true; this.returnOriginalUrl(); this.removeAttribute('custom-color'); this.chartFilter!.setAttribute('hidden', ''); @@ -2062,7 +2064,7 @@ export class SpApplication extends BaseElement { }); this.cutTraceFile!.addEventListener('click', (ev) => { this.validateFileCacheLost(); - if (this.isClear) { + if (this.isClear && !this.isOpenTrace) { let search = document.querySelector('body > sp-application')!.shadowRoot!.querySelector('#lit-search'); let progressEL = document.querySelector("body > sp-application")!.shadowRoot!.querySelector("div > div.search-vessel > lit-progress-bar"); progressEL!.loading = false; @@ -2345,6 +2347,7 @@ export class SpApplication extends BaseElement { }); }); this.isClear = true; + this.isOpenTrace = false; this.mainMenu!.menus = this.mainMenu!.menus; } else { this.isClear = false; -- Gitee From 3075fa44cf0642e2a569f00a0aa19bdc548576ce Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 30 May 2025 10:25:56 +0800 Subject: [PATCH 26/51] =?UTF-8?q?fix:=E6=B1=87=E7=BC=96=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E9=BC=A0=E6=A0=87=E6=82=AC=E5=81=9C=E6=97=B6=E5=B7=A6=E5=8F=B3?= =?UTF-8?q?=E5=B0=96=E6=8B=AC=E5=8F=B7=E6=9C=AA=E8=A2=AB=E8=BD=AC=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/base-ui/table/lit-table.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/base-ui/table/lit-table.ts b/ide/src/base-ui/table/lit-table.ts index d5b41051..339b77a5 100644 --- a/ide/src/base-ui/table/lit-table.ts +++ b/ide/src/base-ui/table/lit-table.ts @@ -1649,7 +1649,7 @@ export class LitTable extends HTMLElement { (child as HTMLElement).title = rowObject.data.time + 'ns'; } else { //@ts-ignore - (child as HTMLElement).title = text; + (child as HTMLElement).title = text.replace(/</g,'<').replace(/>/g,'>'); } } } -- Gitee From 0a8b42a7593f42683325cc767e2440eea60028e3 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 30 May 2025 10:34:45 +0800 Subject: [PATCH 27/51] =?UTF-8?q?fix:=E4=BC=98=E5=8C=96CPU=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/trace/database/ui-worker/cpu/ProcedureWorkerCPU.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ide/src/trace/database/ui-worker/cpu/ProcedureWorkerCPU.ts b/ide/src/trace/database/ui-worker/cpu/ProcedureWorkerCPU.ts index 01730f73..9419ba8e 100644 --- a/ide/src/trace/database/ui-worker/cpu/ProcedureWorkerCPU.ts +++ b/ide/src/trace/database/ui-worker/cpu/ProcedureWorkerCPU.ts @@ -273,7 +273,6 @@ export class CpuStruct extends BaseStruct { ctx.globalAlpha = 1; ctx.fillStyle = '#e0e0e0'; } - ctx.clearRect(data.frame.x, data.frame.y, width, data.frame.height); ctx.fillRect(data.frame.x, data.frame.y, width, data.frame.height); ctx.globalAlpha = 1; CpuStruct.drawText(ctx, data, width, pid, tid); -- Gitee From 46b2687ab0ca732d93268fe25ff37160e7ddea74 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 30 May 2025 16:16:03 +0800 Subject: [PATCH 28/51] =?UTF-8?q?fix:Async=20Call=20Profile=E7=81=AB?= =?UTF-8?q?=E7=84=B0=E5=9B=BE=E9=BC=A0=E6=A0=87=E6=82=AC=E6=B5=AE=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/trace/component/chart/FrameChart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/trace/component/chart/FrameChart.ts b/ide/src/trace/component/chart/FrameChart.ts index 9c0bb5d8..fa96428b 100644 --- a/ide/src/trace/component/chart/FrameChart.ts +++ b/ide/src/trace/component/chart/FrameChart.ts @@ -920,7 +920,7 @@ export class FrameChart extends BaseElement { const label = ChartMode.Count === this._mode ? 'Count' : 'EventCount'; const count = this.getNodeValue(hoverNode); let sourceHint = ''; - if (hoverNode.sourceFile !== '') { + if (hoverNode.sourceFile) { const lines = Array.from(hoverNode.lineNumber).sort((a, b) => a - b).join(','); sourceHint = `Source: ${hoverNode?.sourceFile} : ${lines}
`; } -- Gitee From bbb47f016c18d12cdf825ede9641c92f330f861f Mon Sep 17 00:00:00 2001 From: JustinYT Date: Wed, 4 Jun 2025 14:09:23 +0800 Subject: [PATCH 29/51] fix hiviewdfx_faultloggerd patch for win/linux/mac, CRLF to LF. Signed-off-by: JustinYT --- trace_streamer/pare_third_party.sh | 1 + .../patch_hiperf/hiviewdfx_faultloggerd.patch | 1510 ++++++++++++++++- 2 files changed, 1501 insertions(+), 10 deletions(-) diff --git a/trace_streamer/pare_third_party.sh b/trace_streamer/pare_third_party.sh index a3d03073..ea6a1352 100755 --- a/trace_streamer/pare_third_party.sh +++ b/trace_streamer/pare_third_party.sh @@ -84,6 +84,7 @@ fi if [ ! -d "hiviewdfx/faultloggerd" ];then git clone --depth=1 git@gitee.com:openharmony/hiviewdfx_faultloggerd.git hiviewdfx/faultloggerd/ cd hiviewdfx/faultloggerd + perl -pi -e 's/\r$//' interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp $patch -p1 < ../../../prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch cd ../../ fi diff --git a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch index 42e2c46b..56803cb2 100644 --- a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch +++ b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch @@ -161,18 +161,1508 @@ index b4c84437..86a4bdd1 100644 #else #include diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp -index 9398e59a..d071f2b9 100644 +index 9398e59a..79d230e0 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp +++ b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp -@@ -20,7 +20,7 @@ - #include - #include - #include --#if is_mingw -+#if is_mingw || is_mac - #include "dfx_nonlinux_define.h" - #else - #include +@@ -1,749 +1,749 @@ +-/* +- * Copyright (c) 2021-2025 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. +- */ +- +-#include "dfx_elf.h" +- +-#include +-#include +-#include +-#include +-#include +-#if is_mingw +-#include "dfx_nonlinux_define.h" +-#else +-#include +-#include +-#endif +-#include +-#include +-#include +-#include +- +-#include "dfx_define.h" +-#include "dfx_log.h" +-#include "dfx_instr_statistic.h" +-#include "dfx_util.h" +-#include "dfx_maps.h" +-#include "dfx_trace_dlsym.h" +-#include "dwarf_define.h" +-#include "elf_factory.h" +-#include "string_util.h" +-#include "unwinder_config.h" +- +-namespace OHOS { +-namespace HiviewDFX { +-namespace { +-#undef LOG_DOMAIN +-#undef LOG_TAG +-#define LOG_DOMAIN 0xD002D11 +-#define LOG_TAG "DfxElf" +-#if is_ohos && !is_mingw +-enum HdrSection { +- SECTION_TEXT = 0, +- SECTION_ARMEXIDX = 1, +- SECTION_DYNAMIC = 2, +- SECTION_EHFRAMEHDR = 3 +-}; +-#endif +-} +- +-void DfxElf::Init() +-{ +- uti_.namePtr = 0; +- uti_.format = -1; +- hasTableInfo_ = false; +-} +- +-void DfxElf::Clear() +-{ +- if (elfParse_ != nullptr) { +- elfParse_.reset(); +- elfParse_ = nullptr; +- } +- +- if (mmap_ != nullptr) { +- mmap_->Clear(); +- mmap_.reset(); +- mmap_ = nullptr; +- } +-} +- +-bool DfxElf::InitHeaders() +-{ +- if (mmap_ == nullptr) { +- return false; +- } +- +- if (elfParse_ != nullptr) { +- return true; +- } +- +- uint8_t ident[SELFMAG + 1]; +- if (!Read(0, ident, SELFMAG) || !IsValidElf(ident, SELFMAG)) { +- return false; +- } +- +- if (!Read(EI_CLASS, &classType_, sizeof(uint8_t))) { +- return false; +- } +- +- if (classType_ == ELFCLASS32) { +- elfParse_ = std::unique_ptr(new ElfParser32(mmap_)); +- } else if (classType_ == ELFCLASS64) { +- elfParse_ = std::unique_ptr(new ElfParser64(mmap_)); +- } else { +- DFXLOGW("InitHeaders failed, classType: %{public}d", classType_); +- return false; +- } +- if (elfParse_ != nullptr) { +- valid_ = true; +- elfParse_->InitHeaders(); +- } +- return valid_; +-} +- +-bool DfxElf::IsValid() +-{ +- if (valid_ == false) { +- InitHeaders(); +- } +- return valid_; +-} +- +-uint8_t DfxElf::GetClassType() +-{ +- if (IsValid()) { +- return classType_; +- } +- return ELFCLASSNONE; +-} +- +-ArchType DfxElf::GetArchType() +-{ +- if (IsValid()) { +- elfParse_->GetArchType(); +- } +- return ARCH_UNKNOWN; +-} +- +-int64_t DfxElf::GetLoadBias() +-{ +- if (loadBias_ == 0) { +- if (IsValid()) { +- loadBias_ = elfParse_->GetLoadBias(); +- DFXLOGU("Elf loadBias: %{public}" PRIx64 "", (uint64_t)loadBias_); +- } +- } +- return loadBias_; +-} +- +-uint64_t DfxElf::GetLoadBase(uint64_t mapStart, uint64_t mapOffset) +-{ +- if (loadBase_ == static_cast(-1)) { +- if (IsValid()) { +- DFXLOGU("mapStart: %{public}" PRIx64 ", mapOffset: %{public}" PRIx64 "", +- (uint64_t)mapStart, (uint64_t)mapOffset); +- loadBase_ = mapStart - mapOffset - static_cast(GetLoadBias()); +- DFXLOGU("Elf loadBase: %{public}" PRIx64 "", (uint64_t)loadBase_); +- } +- } +- return loadBase_; +-} +- +-void DfxElf::SetLoadBase(uint64_t base) +-{ +- loadBase_ = base; +-} +- +-void DfxElf::SetBaseOffset(uint64_t offset) +-{ +- baseOffset_ = offset; +-} +- +-uint64_t DfxElf::GetBaseOffset() +-{ +- return baseOffset_; +-} +- +-uint64_t DfxElf::GetStartPc() +-{ +- if (startPc_ == static_cast(-1)) { +- if (IsValid()) { +- auto startVaddr = elfParse_->GetStartVaddr(); +- if (loadBase_ != static_cast(-1) && startVaddr != static_cast(-1)) { +- startPc_ = startVaddr + loadBase_; +- DFXLOGU("Elf startPc: %{public}" PRIx64 "", (uint64_t)startPc_); +- } +- } +- } +- return startPc_; +-} +- +-uint64_t DfxElf::GetStartVaddr() +-{ +- if (IsValid()) { +- return elfParse_->GetStartVaddr(); +- } +- return 0; +-} +- +-uint64_t DfxElf::GetEndPc() +-{ +- if (endPc_ == 0) { +- if (IsValid()) { +- auto endVaddr = elfParse_->GetEndVaddr(); +- if (loadBase_ != static_cast(-1) && endVaddr != 0) { +- endPc_ = endVaddr + loadBase_; +- DFXLOGU("Elf endPc: %{public}" PRIx64 "", (uint64_t)endPc_); +- } +- } +- } +- return endPc_; +-} +- +-uint64_t DfxElf::GetEndVaddr() +-{ +- if (IsValid()) { +- return elfParse_->GetEndVaddr(); +- } +- return 0; +-} +- +-uint64_t DfxElf::GetStartOffset() +-{ +- if (IsValid()) { +- return elfParse_->GetStartOffset(); +- } +- return 0; +-} +- +-uint64_t DfxElf::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset) +-{ +- return (pc - GetLoadBase(mapStart, mapOffset)); +-} +- +-uint64_t DfxElf::GetElfSize() +-{ +- if (!IsValid()) { +- return 0; +- } +- return elfParse_->GetElfSize(); +-} +- +-std::string DfxElf::GetElfName() +-{ +- if (!IsValid()) { +- return ""; +- } +- return elfParse_->GetElfName(); +-} +- +-void DfxElf::SetBuildId(const std::string& buildId) +-{ +- buildId_ = buildId; +-} +- +-std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize) +-{ +- return ElfParser::ParseHexBuildId(noteAddr, noteSize); +-} +- +-std::string DfxElf::GetBuildId() +-{ +- if (buildId_.empty()) { +- if (!IsValid()) { +- return ""; +- } +- return elfParse_->GetBuildId(); +- } +- return buildId_; +-} +- +- +-uintptr_t DfxElf::GetGlobalPointer() +-{ +- if (!IsValid()) { +- return 0; +- } +- return elfParse_->GetGlobalPointer(); +-} +- +-bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName) +-{ +- if (!IsValid()) { +- return false; +- } +- return elfParse_->GetSectionInfo(shdr, secName); +-} +- +-bool DfxElf::GetSectionData(unsigned char* buf, uint64_t size, std::string secName) +-{ +- if (!IsValid()) { +- return false; +- } +- return elfParse_->GetSectionData(buf, size, secName); +-} +- +-GnuDebugDataHdr DfxElf::GetGnuDebugDataHdr() +-{ +- if (!IsValid()) { +- return {}; +- } +- return elfParse_->GetGnuDebugDataHdr(); +-} +- +-bool DfxElf::IsMiniDebugInfoValid() +-{ +- if (miniDebugInfo_ == nullptr) { +-#if defined(ENABLE_MINIDEBUGINFO) +- MiniDebugInfoFactory miniDebugInfoFactory(elfParse_->GetGnuDebugDataHdr()); +- miniDebugInfo_ = miniDebugInfoFactory.Create(); +-#endif +- } +- return miniDebugInfo_ != nullptr; +-} +- +-const std::set& DfxElf::GetFuncSymbols() +-{ +- if (!IsValid() || !funcSymbols_.empty()) { +- return funcSymbols_; +- } +- if (IsMiniDebugInfoValid()) { +- funcSymbols_ = miniDebugInfo_->elfParse_->GetFuncSymbols(); +- DFXLOGU("Get MiniDebugInfo FuncSymbols, size: %{public}zu", funcSymbols_.size()); +- } +- const auto &symbols = elfParse_->GetFuncSymbols(); +- funcSymbols_.insert(symbols.begin(), symbols.end()); +- DFXLOGU("GetFuncSymbols, size: %{public}zu", funcSymbols_.size()); +- return funcSymbols_; +-} +- +-bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol) +-{ +- DFX_TRACE_SCOPED_DLSYM("GetFuncInfoLazily"); +- if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) { +- return true; +- } +- bool findSymbol = elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); +- if (!findSymbol && IsMiniDebugInfoValid()) { +- findSymbol = miniDebugInfo_->elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); +- } +- +- if (findSymbol) { +- funcSymbols_.emplace(elfSymbol); +- DFXLOGU("GetFuncInfoLazily, size: %{public}zu", funcSymbols_.size()); +- } +- return findSymbol; +-} +- +-bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol) +-{ +- if (!IsValid()) { +- return false; +- } +- if (UnwinderConfig::GetEnableLoadSymbolLazily()) { +- return GetFuncInfoLazily(addr, elfSymbol); +- } +- +- const auto &symbols = GetFuncSymbols(); +- return FindFuncSymbol(addr, symbols, elfSymbol); +-} +- +-bool DfxElf::FindFuncSymbol(uint64_t addr, const std::set& symbols, ElfSymbol& elfSymbol) +-{ +- DFX_TRACE_SCOPED_DLSYM("FindFuncSymbol"); +- if (symbols.empty()) { +- return false; +- } +- // Find the first position that is not less than value +- ElfSymbol tmpSym; +- tmpSym.value = addr; +- auto next = symbols.upper_bound(tmpSym); +- if (next != symbols.begin()) { +- next--; +- } +- if (next->value <= addr && addr < (next->value + next->size)) { +- elfSymbol = *next; +- return true; +- } +- return false; +-} +- +-const std::unordered_map& DfxElf::GetPtLoads() +-{ +- return elfParse_->GetPtLoads(); +-} +- +-bool DfxElf::FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti) +-{ +- if (uti == nullptr) { +- return false; +- } +- uti->gp = 0; +- uti->tableData = loadBase + shdr.addr; +- uti->tableLen = shdr.size; +- INSTR_STATISTIC(InstructionEntriesArmExidx, shdr.size, 0); +- uti->format = UNW_INFO_FORMAT_ARM_EXIDX; +- DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, +- (uint64_t)uti->tableData, (int)uti->tableLen); +- return true; +-} +- +-#if is_ohos && !is_mingw +-bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct UnwindTableInfo* uti) +-{ +- if (hdr == nullptr) { +- return false; +- } +- if (hdr->version != DW_EH_VERSION) { +- DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); +- return false; +- } +- +- uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); +- DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, +- (uint64_t)hdr, (uint64_t)ptr); +- auto memory = std::make_shared(UNWIND_TYPE_LOCAL); +- DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, +- (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); +- memory->SetDataOffset(uti->gp); +- MAYBE_UNUSED uintptr_t ehFrameStart = memory->ReadEncodedValue(ptr, hdr->ehFramePtrEnc); +- uintptr_t fdeCount = memory->ReadEncodedValue(ptr, hdr->fdeCountEnc); +- DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, +- (uint64_t)ehFrameStart, (int)fdeCount); +- +- if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { +- DFXLOGU("tableEnc: %{public}x", hdr->tableEnc); +- if (hdr->fdeCountEnc == DW_EH_PE_omit) { +- fdeCount = ~0UL; +- } +- if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { +- DFXLOGE("ehFramePtrEnc(%{public}x) error", hdr->ehFramePtrEnc); +- return false; +- } +- uti->isLinear = true; +- uti->tableLen = fdeCount; +- uti->tableData = ehFrameStart; +- } else { +- uti->isLinear = false; +- uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); +- uti->tableData = ptr; +- uti->segbase = (uintptr_t)hdr; +- } +- uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; +- DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, +- (uint64_t)uti->tableData, (int)uti->tableLen); +- return true; +-} +-#endif +- +-bool DfxElf::FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti) +-{ +- if ((hdr == nullptr) || (uti == nullptr)) { +- return false; +- } +- if (hdr->version != DW_EH_VERSION) { +- DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); +- return false; +- } +- uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); +- DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, +- (uint64_t)hdr, (uint64_t)ptr); +- +- uti->gp = GetGlobalPointer(); +- DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, +- (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); +- mmap_->SetDataOffset(uti->gp); +- auto ptrOffset = ptr - reinterpret_cast(GetMmapPtr()); +- MAYBE_UNUSED uintptr_t ehFrameStart = mmap_->ReadEncodedValue(ptrOffset, hdr->ehFramePtrEnc); +- uintptr_t fdeCount = mmap_->ReadEncodedValue(ptrOffset, hdr->fdeCountEnc); +- DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, +- (uint64_t)ehFrameStart, (int)fdeCount); +- ptr = reinterpret_cast(GetMmapPtr()) + ptrOffset; +- +- if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { +- DFXLOGU("[%{public}d]: tableEnc: %{public}x", __LINE__, hdr->tableEnc); +- if (hdr->fdeCountEnc == DW_EH_PE_omit) { +- fdeCount = ~0UL; +- } +- if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { +- DFXLOGE("[%{public}d]: ehFramePtrEnc(%{public}x) error", __LINE__, hdr->ehFramePtrEnc); +- return false; +- } +- uti->isLinear = true; +- uti->tableLen = fdeCount; +- uti->tableData = shdrBase + ehFrameStart; +- uti->segbase = shdrBase; +- } else { +- uti->isLinear = false; +- uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); +- uti->tableData = shdrBase + ptr - (uintptr_t)hdr; +- uti->segbase = shdrBase; +- } +- uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; +- DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, +- (uint64_t)uti->tableData, (int)uti->tableLen); +- return true; +-} +- +-int DfxElf::FindUnwindTableInfo(uintptr_t pc, std::shared_ptr map, struct UnwindTableInfo& uti) +-{ +- if (hasTableInfo_ && pc >= uti_.startPc && pc < uti_.endPc) { +- uti = uti_; +- DFXLOGU("FindUnwindTableInfo had found"); +- return UNW_ERROR_NONE; +- } +- if (map == nullptr) { +- return UNW_ERROR_INVALID_MAP; +- } +- uintptr_t loadBase = GetLoadBase(map->begin, map->offset); +- uti.startPc = GetStartPc(); +- uti.endPc = GetEndPc(); +- if (pc < uti.startPc || pc >= uti.endPc) { +- DFXLOGU("Elf startPc: %{public}" PRIx64 ", endPc: %{public}" PRIx64 "", +- (uint64_t)uti.startPc, (uint64_t)uti.endPc); +- return UNW_ERROR_PC_NOT_IN_UNWIND_INFO; +- } +- +- ShdrInfo shdr; +-#if defined(__arm__) +- if (GetSectionInfo(shdr, ARM_EXIDX)) { +- hasTableInfo_ = FillUnwindTableByExidx(shdr, loadBase, &uti); +- } +-#endif +- +- if (!hasTableInfo_) { +- struct DwarfEhFrameHdr* hdr = nullptr; +- struct DwarfEhFrameHdr synthHdr; +- if (GetSectionInfo(shdr, EH_FRAME_HDR) && GetMmapPtr() != nullptr) { +- INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); +- hdr = (struct DwarfEhFrameHdr *) (shdr.offset + (char *)GetMmapPtr()); +- } else if (GetSectionInfo(shdr, EH_FRAME) && GetMmapPtr() != nullptr) { +- DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ +- "using synthetic .eh_frame section", __LINE__, map->name.c_str()); +- INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); +- synthHdr.version = DW_EH_VERSION; +- synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | +- ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes +- synthHdr.fdeCountEnc = DW_EH_PE_omit; +- synthHdr.tableEnc = DW_EH_PE_omit; +- synthHdr.ehFrame = (ElfW(Addr))(shdr.offset + (char*)GetMmapPtr()); +- hdr = &synthHdr; +- } +- uintptr_t shdrBase = static_cast(loadBase + shdr.addr); +- hasTableInfo_ = FillUnwindTableByEhhdr(hdr, shdrBase, &uti); +- } +- +- if (hasTableInfo_) { +- uti_ = uti; +- return UNW_ERROR_NONE; +- } +- return UNW_ERROR_NO_UNWIND_INFO; +-} +- +-int DfxElf::FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti) +-{ +-#if is_ohos && !is_mingw +- DlCbData cbData; +- (void)memset_s(&cbData, sizeof(cbData), 0, sizeof(cbData)); +- cbData.pc = pc; +- cbData.uti.format = -1; +- int ret = dl_iterate_phdr(DlPhdrCb, &cbData); +- if (ret > 0) { +- if (cbData.uti.format != -1) { +- uti = cbData.uti; +- return UNW_ERROR_NONE; +- } +- } +- return UNW_ERROR_NO_UNWIND_INFO; +-#else +- return UNW_ERROR_UNSUPPORTED_VERSION; +-#endif +-} +- +-#if is_ohos && !is_mingw +-bool DfxElf::FindSection(struct dl_phdr_info* info, const std::string secName, ShdrInfo& shdr) +-{ +- if (info == nullptr) { +- return false; +- } +- const char* file = info->dlpi_name; +- if (strlen(file) == 0) { +- file = PROC_SELF_EXE_PATH; +- } +- RegularElfFactory elfFactory(file); +- auto elf = elfFactory.Create(); +- if (elf == nullptr) { +- return false; +- } +- +- return elf->GetSectionInfo(shdr, secName); +-} +- +-void DfxElf::ParsePhdr(struct dl_phdr_info* info, const ElfW(Phdr)* (&pHdrSections)[4], const uintptr_t pc) +-{ +- const ElfW(Phdr)* phdr = info->dlpi_phdr; +- for (size_t i = 0; i < info->dlpi_phnum && phdr != nullptr; i++, phdr++) { +- switch (phdr->p_type) { +- case PT_LOAD: { +- ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr; +- if (pc >= vaddr && pc < vaddr + phdr->p_memsz) { +- pHdrSections[SECTION_TEXT] = phdr; +- } +- break; +- } +-#if defined(__arm__) +- case PT_ARM_EXIDX: { +- pHdrSections[SECTION_ARMEXIDX] = phdr; +- break; +- } +-#endif +- case PT_GNU_EH_FRAME: { +- pHdrSections[SECTION_EHFRAMEHDR] = phdr; +- break; +- } +- case PT_DYNAMIC: { +- pHdrSections[SECTION_DYNAMIC] = phdr; +- break; +- } +- default: +- break; +- } +- } +-} +- +-bool DfxElf::ProccessDynamic(const ElfW(Phdr)* pDynamic, ElfW(Addr) loadBase, UnwindTableInfo* uti) +-{ +- ElfW(Dyn)* dyn = reinterpret_cast(pDynamic->p_vaddr + loadBase); +- if (dyn == nullptr) { +- return false; +- } +- for (; dyn->d_tag != DT_NULL; ++dyn) { +- if (dyn->d_tag == DT_PLTGOT) { +- uti->gp = dyn->d_un.d_ptr; +- break; +- } +- } +- return true; +-} +- +-struct DwarfEhFrameHdr* DfxElf::InitHdr(struct DwarfEhFrameHdr& synthHdr, +- struct dl_phdr_info* info, const ElfW(Phdr)* pEhHdr) +-{ +- struct DwarfEhFrameHdr* hdr = nullptr; +- if (pEhHdr) { +- INSTR_STATISTIC(InstructionEntriesEhFrame, pEhHdr->p_memsz, 0); +- hdr = reinterpret_cast(pEhHdr->p_vaddr + info->dlpi_addr); +- } else { +- ShdrInfo shdr; +- if (FindSection(info, EH_FRAME, shdr)) { +- DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ +- "using synthetic .eh_frame section", __LINE__, info->dlpi_name); +- INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); +- synthHdr.version = DW_EH_VERSION; +- synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | +- ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes +- synthHdr.fdeCountEnc = DW_EH_PE_omit; +- synthHdr.tableEnc = DW_EH_PE_omit; +- synthHdr.ehFrame = (ElfW(Addr))(shdr.addr + info->dlpi_addr); +- hdr = &synthHdr; +- } +- } +- return hdr; +-} +- +-int DfxElf::DlPhdrCb(struct dl_phdr_info* info, size_t size, void* data) +-{ +- struct DlCbData* cbData = reinterpret_cast(data); +- if ((info == nullptr) || (cbData == nullptr)) { +- return -1; +- } +- UnwindTableInfo* uti = &cbData->uti; +- uintptr_t pc = cbData->pc; +- const int numOfPhdrSections = 4; +- const ElfW(Phdr)* pHdrSections[numOfPhdrSections] = {nullptr}; +- ParsePhdr(info, pHdrSections, pc); +- +- if (pHdrSections[SECTION_TEXT] == nullptr) { +- return 0; +- } +- ElfW(Addr) loadBase = info->dlpi_addr; +- uti->startPc = pHdrSections[SECTION_TEXT]->p_vaddr + loadBase; +- uti->endPc = uti->startPc + pHdrSections[SECTION_TEXT]->p_memsz; +- DFXLOGU("Elf name: %{public}s", info->dlpi_name); +- uti->namePtr = reinterpret_cast(info->dlpi_name); +- +-#if defined(__arm__) +- if (pHdrSections[SECTION_ARMEXIDX]) { +- ShdrInfo shdr; +- shdr.addr = pHdrSections[SECTION_ARMEXIDX]->p_vaddr; +- shdr.size = pHdrSections[SECTION_ARMEXIDX]->p_memsz; +- return FillUnwindTableByExidx(shdr, loadBase, uti); +- } +-#endif +- +- if (pHdrSections[SECTION_DYNAMIC]) { +- if (!ProccessDynamic(pHdrSections[SECTION_DYNAMIC], loadBase, uti)) { +- return 0; +- } +- } else { +- uti->gp = 0; +- } +- +- struct DwarfEhFrameHdr synthHdr; +- struct DwarfEhFrameHdr* hdr = InitHdr(synthHdr, info, pHdrSections[SECTION_EHFRAMEHDR]); +- +- return FillUnwindTableByEhhdrLocal(hdr, uti); +-} +-#endif +- +-bool DfxElf::Read(uintptr_t pos, void* buf, size_t size) +-{ +- if ((mmap_ != nullptr) && (mmap_->Read(pos, buf, size) == size)) { +- return true; +- } +- return false; +-} +- +-const uint8_t* DfxElf::GetMmapPtr() +-{ +- if (mmap_ == nullptr) { +- return nullptr; +- } +- return static_cast(mmap_->Get()); +-} +- +-size_t DfxElf::GetMmapSize() +-{ +- if (mmap_ == nullptr) { +- return 0; +- } +- return mmap_->Size(); +-} +- +-bool DfxElf::IsValidElf(const void* ptr, size_t size) +-{ +- if (ptr == nullptr) { +- return false; +- } +- +- if (memcmp(ptr, ELFMAG, size) != 0) { +- DFXLOGD("Invalid elf hdr?"); +- return false; +- } +- return true; +-} +-} // namespace HiviewDFX +-} // namespace OHOS ++/* ++ * Copyright (c) 2021-2025 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. ++ */ ++ ++#include "dfx_elf.h" ++ ++#include ++#include ++#include ++#include ++#include ++#if is_mingw || is_mac ++#include "dfx_nonlinux_define.h" ++#else ++#include ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++#include "dfx_define.h" ++#include "dfx_log.h" ++#include "dfx_instr_statistic.h" ++#include "dfx_util.h" ++#include "dfx_maps.h" ++#include "dfx_trace_dlsym.h" ++#include "dwarf_define.h" ++#include "elf_factory.h" ++#include "string_util.h" ++#include "unwinder_config.h" ++ ++namespace OHOS { ++namespace HiviewDFX { ++namespace { ++#undef LOG_DOMAIN ++#undef LOG_TAG ++#define LOG_DOMAIN 0xD002D11 ++#define LOG_TAG "DfxElf" ++#if is_ohos && !is_mingw ++enum HdrSection { ++ SECTION_TEXT = 0, ++ SECTION_ARMEXIDX = 1, ++ SECTION_DYNAMIC = 2, ++ SECTION_EHFRAMEHDR = 3 ++}; ++#endif ++} ++ ++void DfxElf::Init() ++{ ++ uti_.namePtr = 0; ++ uti_.format = -1; ++ hasTableInfo_ = false; ++} ++ ++void DfxElf::Clear() ++{ ++ if (elfParse_ != nullptr) { ++ elfParse_.reset(); ++ elfParse_ = nullptr; ++ } ++ ++ if (mmap_ != nullptr) { ++ mmap_->Clear(); ++ mmap_.reset(); ++ mmap_ = nullptr; ++ } ++} ++ ++bool DfxElf::InitHeaders() ++{ ++ if (mmap_ == nullptr) { ++ return false; ++ } ++ ++ if (elfParse_ != nullptr) { ++ return true; ++ } ++ ++ uint8_t ident[SELFMAG + 1]; ++ if (!Read(0, ident, SELFMAG) || !IsValidElf(ident, SELFMAG)) { ++ return false; ++ } ++ ++ if (!Read(EI_CLASS, &classType_, sizeof(uint8_t))) { ++ return false; ++ } ++ ++ if (classType_ == ELFCLASS32) { ++ elfParse_ = std::unique_ptr(new ElfParser32(mmap_)); ++ } else if (classType_ == ELFCLASS64) { ++ elfParse_ = std::unique_ptr(new ElfParser64(mmap_)); ++ } else { ++ DFXLOGW("InitHeaders failed, classType: %{public}d", classType_); ++ return false; ++ } ++ if (elfParse_ != nullptr) { ++ valid_ = true; ++ elfParse_->InitHeaders(); ++ } ++ return valid_; ++} ++ ++bool DfxElf::IsValid() ++{ ++ if (valid_ == false) { ++ InitHeaders(); ++ } ++ return valid_; ++} ++ ++uint8_t DfxElf::GetClassType() ++{ ++ if (IsValid()) { ++ return classType_; ++ } ++ return ELFCLASSNONE; ++} ++ ++ArchType DfxElf::GetArchType() ++{ ++ if (IsValid()) { ++ elfParse_->GetArchType(); ++ } ++ return ARCH_UNKNOWN; ++} ++ ++int64_t DfxElf::GetLoadBias() ++{ ++ if (loadBias_ == 0) { ++ if (IsValid()) { ++ loadBias_ = elfParse_->GetLoadBias(); ++ DFXLOGU("Elf loadBias: %{public}" PRIx64 "", (uint64_t)loadBias_); ++ } ++ } ++ return loadBias_; ++} ++ ++uint64_t DfxElf::GetLoadBase(uint64_t mapStart, uint64_t mapOffset) ++{ ++ if (loadBase_ == static_cast(-1)) { ++ if (IsValid()) { ++ DFXLOGU("mapStart: %{public}" PRIx64 ", mapOffset: %{public}" PRIx64 "", ++ (uint64_t)mapStart, (uint64_t)mapOffset); ++ loadBase_ = mapStart - mapOffset - static_cast(GetLoadBias()); ++ DFXLOGU("Elf loadBase: %{public}" PRIx64 "", (uint64_t)loadBase_); ++ } ++ } ++ return loadBase_; ++} ++ ++void DfxElf::SetLoadBase(uint64_t base) ++{ ++ loadBase_ = base; ++} ++ ++void DfxElf::SetBaseOffset(uint64_t offset) ++{ ++ baseOffset_ = offset; ++} ++ ++uint64_t DfxElf::GetBaseOffset() ++{ ++ return baseOffset_; ++} ++ ++uint64_t DfxElf::GetStartPc() ++{ ++ if (startPc_ == static_cast(-1)) { ++ if (IsValid()) { ++ auto startVaddr = elfParse_->GetStartVaddr(); ++ if (loadBase_ != static_cast(-1) && startVaddr != static_cast(-1)) { ++ startPc_ = startVaddr + loadBase_; ++ DFXLOGU("Elf startPc: %{public}" PRIx64 "", (uint64_t)startPc_); ++ } ++ } ++ } ++ return startPc_; ++} ++ ++uint64_t DfxElf::GetStartVaddr() ++{ ++ if (IsValid()) { ++ return elfParse_->GetStartVaddr(); ++ } ++ return 0; ++} ++ ++uint64_t DfxElf::GetEndPc() ++{ ++ if (endPc_ == 0) { ++ if (IsValid()) { ++ auto endVaddr = elfParse_->GetEndVaddr(); ++ if (loadBase_ != static_cast(-1) && endVaddr != 0) { ++ endPc_ = endVaddr + loadBase_; ++ DFXLOGU("Elf endPc: %{public}" PRIx64 "", (uint64_t)endPc_); ++ } ++ } ++ } ++ return endPc_; ++} ++ ++uint64_t DfxElf::GetEndVaddr() ++{ ++ if (IsValid()) { ++ return elfParse_->GetEndVaddr(); ++ } ++ return 0; ++} ++ ++uint64_t DfxElf::GetStartOffset() ++{ ++ if (IsValid()) { ++ return elfParse_->GetStartOffset(); ++ } ++ return 0; ++} ++ ++uint64_t DfxElf::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset) ++{ ++ return (pc - GetLoadBase(mapStart, mapOffset)); ++} ++ ++uint64_t DfxElf::GetElfSize() ++{ ++ if (!IsValid()) { ++ return 0; ++ } ++ return elfParse_->GetElfSize(); ++} ++ ++std::string DfxElf::GetElfName() ++{ ++ if (!IsValid()) { ++ return ""; ++ } ++ return elfParse_->GetElfName(); ++} ++ ++void DfxElf::SetBuildId(const std::string& buildId) ++{ ++ buildId_ = buildId; ++} ++ ++std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize) ++{ ++ return ElfParser::ParseHexBuildId(noteAddr, noteSize); ++} ++ ++std::string DfxElf::GetBuildId() ++{ ++ if (buildId_.empty()) { ++ if (!IsValid()) { ++ return ""; ++ } ++ return elfParse_->GetBuildId(); ++ } ++ return buildId_; ++} ++ ++ ++uintptr_t DfxElf::GetGlobalPointer() ++{ ++ if (!IsValid()) { ++ return 0; ++ } ++ return elfParse_->GetGlobalPointer(); ++} ++ ++bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName) ++{ ++ if (!IsValid()) { ++ return false; ++ } ++ return elfParse_->GetSectionInfo(shdr, secName); ++} ++ ++bool DfxElf::GetSectionData(unsigned char* buf, uint64_t size, std::string secName) ++{ ++ if (!IsValid()) { ++ return false; ++ } ++ return elfParse_->GetSectionData(buf, size, secName); ++} ++ ++GnuDebugDataHdr DfxElf::GetGnuDebugDataHdr() ++{ ++ if (!IsValid()) { ++ return {}; ++ } ++ return elfParse_->GetGnuDebugDataHdr(); ++} ++ ++bool DfxElf::IsMiniDebugInfoValid() ++{ ++ if (miniDebugInfo_ == nullptr) { ++#if defined(ENABLE_MINIDEBUGINFO) ++ MiniDebugInfoFactory miniDebugInfoFactory(elfParse_->GetGnuDebugDataHdr()); ++ miniDebugInfo_ = miniDebugInfoFactory.Create(); ++#endif ++ } ++ return miniDebugInfo_ != nullptr; ++} ++ ++const std::set& DfxElf::GetFuncSymbols() ++{ ++ if (!IsValid() || !funcSymbols_.empty()) { ++ return funcSymbols_; ++ } ++ if (IsMiniDebugInfoValid()) { ++ funcSymbols_ = miniDebugInfo_->elfParse_->GetFuncSymbols(); ++ DFXLOGU("Get MiniDebugInfo FuncSymbols, size: %{public}zu", funcSymbols_.size()); ++ } ++ const auto &symbols = elfParse_->GetFuncSymbols(); ++ funcSymbols_.insert(symbols.begin(), symbols.end()); ++ DFXLOGU("GetFuncSymbols, size: %{public}zu", funcSymbols_.size()); ++ return funcSymbols_; ++} ++ ++bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol) ++{ ++ DFX_TRACE_SCOPED_DLSYM("GetFuncInfoLazily"); ++ if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) { ++ return true; ++ } ++ bool findSymbol = elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); ++ if (!findSymbol && IsMiniDebugInfoValid()) { ++ findSymbol = miniDebugInfo_->elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); ++ } ++ ++ if (findSymbol) { ++ funcSymbols_.emplace(elfSymbol); ++ DFXLOGU("GetFuncInfoLazily, size: %{public}zu", funcSymbols_.size()); ++ } ++ return findSymbol; ++} ++ ++bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol) ++{ ++ if (!IsValid()) { ++ return false; ++ } ++ if (UnwinderConfig::GetEnableLoadSymbolLazily()) { ++ return GetFuncInfoLazily(addr, elfSymbol); ++ } ++ ++ const auto &symbols = GetFuncSymbols(); ++ return FindFuncSymbol(addr, symbols, elfSymbol); ++} ++ ++bool DfxElf::FindFuncSymbol(uint64_t addr, const std::set& symbols, ElfSymbol& elfSymbol) ++{ ++ DFX_TRACE_SCOPED_DLSYM("FindFuncSymbol"); ++ if (symbols.empty()) { ++ return false; ++ } ++ // Find the first position that is not less than value ++ ElfSymbol tmpSym; ++ tmpSym.value = addr; ++ auto next = symbols.upper_bound(tmpSym); ++ if (next != symbols.begin()) { ++ next--; ++ } ++ if (next->value <= addr && addr < (next->value + next->size)) { ++ elfSymbol = *next; ++ return true; ++ } ++ return false; ++} ++ ++const std::unordered_map& DfxElf::GetPtLoads() ++{ ++ return elfParse_->GetPtLoads(); ++} ++ ++bool DfxElf::FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti) ++{ ++ if (uti == nullptr) { ++ return false; ++ } ++ uti->gp = 0; ++ uti->tableData = loadBase + shdr.addr; ++ uti->tableLen = shdr.size; ++ INSTR_STATISTIC(InstructionEntriesArmExidx, shdr.size, 0); ++ uti->format = UNW_INFO_FORMAT_ARM_EXIDX; ++ DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, ++ (uint64_t)uti->tableData, (int)uti->tableLen); ++ return true; ++} ++ ++#if is_ohos && !is_mingw ++bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct UnwindTableInfo* uti) ++{ ++ if (hdr == nullptr) { ++ return false; ++ } ++ if (hdr->version != DW_EH_VERSION) { ++ DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); ++ return false; ++ } ++ ++ uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); ++ DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, ++ (uint64_t)hdr, (uint64_t)ptr); ++ auto memory = std::make_shared(UNWIND_TYPE_LOCAL); ++ DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, ++ (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); ++ memory->SetDataOffset(uti->gp); ++ MAYBE_UNUSED uintptr_t ehFrameStart = memory->ReadEncodedValue(ptr, hdr->ehFramePtrEnc); ++ uintptr_t fdeCount = memory->ReadEncodedValue(ptr, hdr->fdeCountEnc); ++ DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, ++ (uint64_t)ehFrameStart, (int)fdeCount); ++ ++ if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { ++ DFXLOGU("tableEnc: %{public}x", hdr->tableEnc); ++ if (hdr->fdeCountEnc == DW_EH_PE_omit) { ++ fdeCount = ~0UL; ++ } ++ if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { ++ DFXLOGE("ehFramePtrEnc(%{public}x) error", hdr->ehFramePtrEnc); ++ return false; ++ } ++ uti->isLinear = true; ++ uti->tableLen = fdeCount; ++ uti->tableData = ehFrameStart; ++ } else { ++ uti->isLinear = false; ++ uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); ++ uti->tableData = ptr; ++ uti->segbase = (uintptr_t)hdr; ++ } ++ uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; ++ DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, ++ (uint64_t)uti->tableData, (int)uti->tableLen); ++ return true; ++} ++#endif ++ ++bool DfxElf::FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti) ++{ ++ if ((hdr == nullptr) || (uti == nullptr)) { ++ return false; ++ } ++ if (hdr->version != DW_EH_VERSION) { ++ DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version); ++ return false; ++ } ++ uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); ++ DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, ++ (uint64_t)hdr, (uint64_t)ptr); ++ ++ uti->gp = GetGlobalPointer(); ++ DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, ++ (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); ++ mmap_->SetDataOffset(uti->gp); ++ auto ptrOffset = ptr - reinterpret_cast(GetMmapPtr()); ++ MAYBE_UNUSED uintptr_t ehFrameStart = mmap_->ReadEncodedValue(ptrOffset, hdr->ehFramePtrEnc); ++ uintptr_t fdeCount = mmap_->ReadEncodedValue(ptrOffset, hdr->fdeCountEnc); ++ DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__, ++ (uint64_t)ehFrameStart, (int)fdeCount); ++ ptr = reinterpret_cast(GetMmapPtr()) + ptrOffset; ++ ++ if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) { ++ DFXLOGU("[%{public}d]: tableEnc: %{public}x", __LINE__, hdr->tableEnc); ++ if (hdr->fdeCountEnc == DW_EH_PE_omit) { ++ fdeCount = ~0UL; ++ } ++ if (hdr->ehFramePtrEnc == DW_EH_PE_omit) { ++ DFXLOGE("[%{public}d]: ehFramePtrEnc(%{public}x) error", __LINE__, hdr->ehFramePtrEnc); ++ return false; ++ } ++ uti->isLinear = true; ++ uti->tableLen = fdeCount; ++ uti->tableData = shdrBase + ehFrameStart; ++ uti->segbase = shdrBase; ++ } else { ++ uti->isLinear = false; ++ uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t); ++ uti->tableData = shdrBase + ptr - (uintptr_t)hdr; ++ uti->segbase = shdrBase; ++ } ++ uti->format = UNW_INFO_FORMAT_REMOTE_TABLE; ++ DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__, ++ (uint64_t)uti->tableData, (int)uti->tableLen); ++ return true; ++} ++ ++int DfxElf::FindUnwindTableInfo(uintptr_t pc, std::shared_ptr map, struct UnwindTableInfo& uti) ++{ ++ if (hasTableInfo_ && pc >= uti_.startPc && pc < uti_.endPc) { ++ uti = uti_; ++ DFXLOGU("FindUnwindTableInfo had found"); ++ return UNW_ERROR_NONE; ++ } ++ if (map == nullptr) { ++ return UNW_ERROR_INVALID_MAP; ++ } ++ uintptr_t loadBase = GetLoadBase(map->begin, map->offset); ++ uti.startPc = GetStartPc(); ++ uti.endPc = GetEndPc(); ++ if (pc < uti.startPc || pc >= uti.endPc) { ++ DFXLOGU("Elf startPc: %{public}" PRIx64 ", endPc: %{public}" PRIx64 "", ++ (uint64_t)uti.startPc, (uint64_t)uti.endPc); ++ return UNW_ERROR_PC_NOT_IN_UNWIND_INFO; ++ } ++ ++ ShdrInfo shdr; ++#if defined(__arm__) ++ if (GetSectionInfo(shdr, ARM_EXIDX)) { ++ hasTableInfo_ = FillUnwindTableByExidx(shdr, loadBase, &uti); ++ } ++#endif ++ ++ if (!hasTableInfo_) { ++ struct DwarfEhFrameHdr* hdr = nullptr; ++ struct DwarfEhFrameHdr synthHdr; ++ if (GetSectionInfo(shdr, EH_FRAME_HDR) && GetMmapPtr() != nullptr) { ++ INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); ++ hdr = (struct DwarfEhFrameHdr *) (shdr.offset + (char *)GetMmapPtr()); ++ } else if (GetSectionInfo(shdr, EH_FRAME) && GetMmapPtr() != nullptr) { ++ DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ ++ "using synthetic .eh_frame section", __LINE__, map->name.c_str()); ++ INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); ++ synthHdr.version = DW_EH_VERSION; ++ synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | ++ ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes ++ synthHdr.fdeCountEnc = DW_EH_PE_omit; ++ synthHdr.tableEnc = DW_EH_PE_omit; ++ synthHdr.ehFrame = (ElfW(Addr))(shdr.offset + (char*)GetMmapPtr()); ++ hdr = &synthHdr; ++ } ++ uintptr_t shdrBase = static_cast(loadBase + shdr.addr); ++ hasTableInfo_ = FillUnwindTableByEhhdr(hdr, shdrBase, &uti); ++ } ++ ++ if (hasTableInfo_) { ++ uti_ = uti; ++ return UNW_ERROR_NONE; ++ } ++ return UNW_ERROR_NO_UNWIND_INFO; ++} ++ ++int DfxElf::FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti) ++{ ++#if is_ohos && !is_mingw ++ DlCbData cbData; ++ (void)memset_s(&cbData, sizeof(cbData), 0, sizeof(cbData)); ++ cbData.pc = pc; ++ cbData.uti.format = -1; ++ int ret = dl_iterate_phdr(DlPhdrCb, &cbData); ++ if (ret > 0) { ++ if (cbData.uti.format != -1) { ++ uti = cbData.uti; ++ return UNW_ERROR_NONE; ++ } ++ } ++ return UNW_ERROR_NO_UNWIND_INFO; ++#else ++ return UNW_ERROR_UNSUPPORTED_VERSION; ++#endif ++} ++ ++#if is_ohos && !is_mingw ++bool DfxElf::FindSection(struct dl_phdr_info* info, const std::string secName, ShdrInfo& shdr) ++{ ++ if (info == nullptr) { ++ return false; ++ } ++ const char* file = info->dlpi_name; ++ if (strlen(file) == 0) { ++ file = PROC_SELF_EXE_PATH; ++ } ++ RegularElfFactory elfFactory(file); ++ auto elf = elfFactory.Create(); ++ if (elf == nullptr) { ++ return false; ++ } ++ ++ return elf->GetSectionInfo(shdr, secName); ++} ++ ++void DfxElf::ParsePhdr(struct dl_phdr_info* info, const ElfW(Phdr)* (&pHdrSections)[4], const uintptr_t pc) ++{ ++ const ElfW(Phdr)* phdr = info->dlpi_phdr; ++ for (size_t i = 0; i < info->dlpi_phnum && phdr != nullptr; i++, phdr++) { ++ switch (phdr->p_type) { ++ case PT_LOAD: { ++ ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr; ++ if (pc >= vaddr && pc < vaddr + phdr->p_memsz) { ++ pHdrSections[SECTION_TEXT] = phdr; ++ } ++ break; ++ } ++#if defined(__arm__) ++ case PT_ARM_EXIDX: { ++ pHdrSections[SECTION_ARMEXIDX] = phdr; ++ break; ++ } ++#endif ++ case PT_GNU_EH_FRAME: { ++ pHdrSections[SECTION_EHFRAMEHDR] = phdr; ++ break; ++ } ++ case PT_DYNAMIC: { ++ pHdrSections[SECTION_DYNAMIC] = phdr; ++ break; ++ } ++ default: ++ break; ++ } ++ } ++} ++ ++bool DfxElf::ProccessDynamic(const ElfW(Phdr)* pDynamic, ElfW(Addr) loadBase, UnwindTableInfo* uti) ++{ ++ ElfW(Dyn)* dyn = reinterpret_cast(pDynamic->p_vaddr + loadBase); ++ if (dyn == nullptr) { ++ return false; ++ } ++ for (; dyn->d_tag != DT_NULL; ++dyn) { ++ if (dyn->d_tag == DT_PLTGOT) { ++ uti->gp = dyn->d_un.d_ptr; ++ break; ++ } ++ } ++ return true; ++} ++ ++struct DwarfEhFrameHdr* DfxElf::InitHdr(struct DwarfEhFrameHdr& synthHdr, ++ struct dl_phdr_info* info, const ElfW(Phdr)* pEhHdr) ++{ ++ struct DwarfEhFrameHdr* hdr = nullptr; ++ if (pEhHdr) { ++ INSTR_STATISTIC(InstructionEntriesEhFrame, pEhHdr->p_memsz, 0); ++ hdr = reinterpret_cast(pEhHdr->p_vaddr + info->dlpi_addr); ++ } else { ++ ShdrInfo shdr; ++ if (FindSection(info, EH_FRAME, shdr)) { ++ DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \ ++ "using synthetic .eh_frame section", __LINE__, info->dlpi_name); ++ INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0); ++ synthHdr.version = DW_EH_VERSION; ++ synthHdr.ehFramePtrEnc = DW_EH_PE_absptr | ++ ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes ++ synthHdr.fdeCountEnc = DW_EH_PE_omit; ++ synthHdr.tableEnc = DW_EH_PE_omit; ++ synthHdr.ehFrame = (ElfW(Addr))(shdr.addr + info->dlpi_addr); ++ hdr = &synthHdr; ++ } ++ } ++ return hdr; ++} ++ ++int DfxElf::DlPhdrCb(struct dl_phdr_info* info, size_t size, void* data) ++{ ++ struct DlCbData* cbData = reinterpret_cast(data); ++ if ((info == nullptr) || (cbData == nullptr)) { ++ return -1; ++ } ++ UnwindTableInfo* uti = &cbData->uti; ++ uintptr_t pc = cbData->pc; ++ const int numOfPhdrSections = 4; ++ const ElfW(Phdr)* pHdrSections[numOfPhdrSections] = {nullptr}; ++ ParsePhdr(info, pHdrSections, pc); ++ ++ if (pHdrSections[SECTION_TEXT] == nullptr) { ++ return 0; ++ } ++ ElfW(Addr) loadBase = info->dlpi_addr; ++ uti->startPc = pHdrSections[SECTION_TEXT]->p_vaddr + loadBase; ++ uti->endPc = uti->startPc + pHdrSections[SECTION_TEXT]->p_memsz; ++ DFXLOGU("Elf name: %{public}s", info->dlpi_name); ++ uti->namePtr = reinterpret_cast(info->dlpi_name); ++ ++#if defined(__arm__) ++ if (pHdrSections[SECTION_ARMEXIDX]) { ++ ShdrInfo shdr; ++ shdr.addr = pHdrSections[SECTION_ARMEXIDX]->p_vaddr; ++ shdr.size = pHdrSections[SECTION_ARMEXIDX]->p_memsz; ++ return FillUnwindTableByExidx(shdr, loadBase, uti); ++ } ++#endif ++ ++ if (pHdrSections[SECTION_DYNAMIC]) { ++ if (!ProccessDynamic(pHdrSections[SECTION_DYNAMIC], loadBase, uti)) { ++ return 0; ++ } ++ } else { ++ uti->gp = 0; ++ } ++ ++ struct DwarfEhFrameHdr synthHdr; ++ struct DwarfEhFrameHdr* hdr = InitHdr(synthHdr, info, pHdrSections[SECTION_EHFRAMEHDR]); ++ ++ return FillUnwindTableByEhhdrLocal(hdr, uti); ++} ++#endif ++ ++bool DfxElf::Read(uintptr_t pos, void* buf, size_t size) ++{ ++ if ((mmap_ != nullptr) && (mmap_->Read(pos, buf, size) == size)) { ++ return true; ++ } ++ return false; ++} ++ ++const uint8_t* DfxElf::GetMmapPtr() ++{ ++ if (mmap_ == nullptr) { ++ return nullptr; ++ } ++ return static_cast(mmap_->Get()); ++} ++ ++size_t DfxElf::GetMmapSize() ++{ ++ if (mmap_ == nullptr) { ++ return 0; ++ } ++ return mmap_->Size(); ++} ++ ++bool DfxElf::IsValidElf(const void* ptr, size_t size) ++{ ++ if (ptr == nullptr) { ++ return false; ++ } ++ ++ if (memcmp(ptr, ELFMAG, size) != 0) { ++ DFXLOGD("Invalid elf hdr?"); ++ return false; ++ } ++ return true; ++} ++} // namespace HiviewDFX ++} // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp index cbe67062..52ced531 100644 --- a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp -- Gitee From 9b95a2caf195d791dec427a09ba4214511991da6 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Fri, 6 Jun 2025 13:59:40 +0800 Subject: [PATCH 30/51] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dsyscall=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E5=9C=A8=E6=B8=85=E9=99=A4=E7=BC=93=E5=AD=98=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E7=AC=AC=E4=B8=80=E6=AC=A1=E5=8A=A0=E8=BD=BDtrace?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8D=E7=94=9F=E6=95=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: JustinYT --- ide/src/base-ui/select/LitSelectV.ts | 34 +++++++++++--- ide/src/trace/component/SpFlags.ts | 44 +++++++++++-------- .../trace/component/trace/base/TraceRow.ts | 2 +- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/ide/src/base-ui/select/LitSelectV.ts b/ide/src/base-ui/select/LitSelectV.ts index 4a67e03a..a9cb856b 100644 --- a/ide/src/base-ui/select/LitSelectV.ts +++ b/ide/src/base-ui/select/LitSelectV.ts @@ -20,6 +20,7 @@ import { selectHtmlStr, selectVHtmlStr } from './LitSelectHtml'; @element('lit-select-v') export class LitSelectV extends BaseElement { showItems: Array = []; + ignoreValues: Array = []; itemValue: Array = []; customItem: Array = []; private focused: unknown; @@ -147,6 +148,28 @@ export class LitSelectV extends BaseElement { } } + setIgnoreValues(values: string[]) { + this.ignoreValues = values; + } + + setSelectedOptions(selectArray: Array) { + let allSelected = true; + this.shadowRoot?.querySelectorAll('lit-select-option').forEach((a) => { + if (selectArray.includes(a.textContent!)) { + a.setAttribute('selected', ''); + } else { + allSelected = false; + a.removeAttribute('selected'); + } + }); + this.all = allSelected; + selectArray.forEach((i) => { + this.showItems.push(i); + }); + // @ts-ignore + this.selectVInputEl.value = selectArray.filter(it => !this.ignoreValues.includes(it)); + } + initDataItem(selectVDataItem: Array): void { selectVDataItem.forEach((item) => { let selectVOption = document.createElement('lit-select-option'); @@ -263,7 +286,7 @@ export class LitSelectV extends BaseElement { let number = this.showItems.indexOf(a.textContent!); if (number > -1) { this.showItems!.splice(number, 1); // @ts-ignore - this.selectVInputEl!.value = this.showItems; + this.selectVInputEl!.value = this.showItems.filter(it => !this.ignoreValues.includes(it)); } this.all = false; querySelector.removeAttribute('selected'); @@ -274,7 +297,7 @@ export class LitSelectV extends BaseElement { let value = this.showItems.indexOf(a.textContent!); if (index > -1 && value === -1) { this.showItems.push(a.textContent!); // @ts-ignore - this.selectVInputEl!.value = this.showItems; + this.selectVInputEl!.value = this.showItems.filter(it => !this.ignoreValues.includes(it)); } if (this.showItems.length >= this.itemValue.length) { querySelector.setAttribute('selected', ''); @@ -344,10 +367,11 @@ export class LitSelectV extends BaseElement { }); if (this.customItem.length > 0) { // @ts-ignore - this.selectVInputEl.value = this.customItem.concat(this.showItems); + this.selectVInputEl.value = this.customItem.concat(this.showItems) + .filter(it => !this.ignoreValues.includes(it)); } else { // @ts-ignore - this.selectVInputEl.value = this.showItems; + this.selectVInputEl.value = this.showItems.filter(it => !this.ignoreValues.includes(it)); } }); }); @@ -363,7 +387,7 @@ export class LitSelectV extends BaseElement { this.itemValue.forEach((i) => { this.showItems.push(i); }); // @ts-ignore - this.selectVInputEl.value = this.itemValue; + this.selectVInputEl.value = this.itemValue.filter(it => !this.ignoreValues.includes(it));; } else { this.shadowRoot?.querySelectorAll('lit-select-option').forEach((i) => { i.removeAttribute('selected'); diff --git a/ide/src/trace/component/SpFlags.ts b/ide/src/trace/component/SpFlags.ts index e8ebe0f8..8d9594c8 100644 --- a/ide/src/trace/component/SpFlags.ts +++ b/ide/src/trace/component/SpFlags.ts @@ -56,13 +56,11 @@ export class SpFlags extends BaseElement { connectedCallback(): void { - this.systemCallInput?.addEventListener('mousedown', this.systemCallSelectMousedownHandler); this.systemCallSelect?.addEventListener('blur', this.systemCallSelectBlurHandler); } disconnectedCallback(): void { super.disconnectedCallback(); - this.systemCallInput?.removeEventListener('mousedown', this.systemCallSelectMousedownHandler); this.systemCallSelect?.removeEventListener('blur', this.systemCallSelectBlurHandler); } @@ -78,12 +76,25 @@ export class SpFlags extends BaseElement { } private updateSystemCallSelect(): void { + const selectedArr = FlagsConfig.getSystemcallEventId('SystemParsing'); + let checkAll = true; + systemCallConfigList[0].selectArray = Array.from(SysCallMap.entries()) + .map(([id, name]) => { + if (!selectedArr.includes(id)) { + checkAll = false; + } + return `${name}`; + }); + this.systemCallSelect?.dataSource(systemCallConfigList[0].selectArray, 'ALL-SystemCall'); + this.systemCallSelect?.setIgnoreValues(['ALL-SystemCall']); if (this.systemCallSwitch?.title === 'System Calls' && this.systemCallSwitch.selectedOptions[0].value === 'Enabled') { this.systemCallSelect?.removeAttribute('disabled'); - this.systemCallSelect?.dataSource([], ''); + const arr = checkAll ? ['ALL-SystemCall' ] : []; + FlagsConfig.getSystemcallEventId('SystemParsing').forEach(it => arr.push(SysCallMap.get(it) || '')); + this.systemCallSelect?.setSelectedOptions(arr); } else { this.systemCallSelect?.setAttribute('disabled', 'disabled'); - this.systemCallSelect?.dataSource([], ''); + this.systemCallSelect?.setSelectedOptions([]); } } @@ -107,13 +118,6 @@ export class SpFlags extends BaseElement { this.systemCallEventId.push(systemCallEventId); }; - private systemCallSelectMousedownHandler = (): void => { - if (this.systemCallSwitch) - systemCallConfigList[0].selectArray = Array.from(SysCallMap.entries()) - .map(([id, name]) => `${name}`); - this.systemCallSelect?.dataSource(systemCallConfigList[0].selectArray, 'ALL-SystemCall') - }; - initHtml(): string { return SpFlagHtml; } @@ -162,10 +166,15 @@ export class SpFlags extends BaseElement { this.xiaoLubanEl?.removeAttribute('enabled'); } } - if (configSelect.title === 'System Calls' && configSelect.selectedOptions[0].value === 'Enabled') { - this.systemCallSelect?.removeAttribute('disabled'); - } else { - this.systemCallSelect?.setAttribute('disabled', 'disabled'); + if (configSelect.title === 'System Calls') { + if (configSelect.selectedOptions[0].value === 'Enabled') { + this.systemCallSelect?.removeAttribute('disabled'); + } else { + this.systemCallSelect?.setAttribute('disabled', 'disabled'); + this.systemCallEventId = []; + FlagsConfig.updateSystemcallEventId([], 'SystemParsing'); + this.systemCallSelect?.setSelectedOptions([]); + } } }); let userIdInput: HTMLInputElement | null | undefined = this.shadowRoot?.querySelector('#user_id_input'); @@ -593,13 +602,12 @@ export class FlagsConfig { static getSystemcallEventId(value: string): number[] { let list = window.localStorage.getItem(FlagsConfig.SYSTEM_PRASE); - return JSON.parse(list!); + return JSON.parse(list!) || []; } static updateSystemcallEventId(systemCallEventId: number[], value: unknown): void { - let systemcallEventId = window.localStorage.getItem(FlagsConfig.SYSTEM_PRASE); let systemCallEventIdArray:number[] = []; - if (systemcallEventId !== null) { + if (systemCallEventId !== null) { systemCallEventIdArray = systemCallEventId; } window.localStorage.setItem(FlagsConfig.SYSTEM_PRASE, JSON.stringify(systemCallEventIdArray)); diff --git a/ide/src/trace/component/trace/base/TraceRow.ts b/ide/src/trace/component/trace/base/TraceRow.ts index ea5fec73..c5873d74 100644 --- a/ide/src/trace/component/trace/base/TraceRow.ts +++ b/ide/src/trace/component/trace/base/TraceRow.ts @@ -1045,7 +1045,7 @@ export class TraceRow extends HTMLElement { } this._rowSettingCheckBoxList && this._rowSettingCheckBoxList.forEach((item) => { checkboxHtml += `
- +
`; }); this._rowSettingCheckedBoxList = new Array(this._rowSettingCheckBoxList?.length).fill(appendAll); -- Gitee From b89bee4975fc551a10ce4c841dbe4bff9fefc348 Mon Sep 17 00:00:00 2001 From: zhangzhuozhou Date: Thu, 12 Jun 2025 09:27:50 +0800 Subject: [PATCH 31/51] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Dffrt=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhuozhou --- trace_streamer/src/filter/config_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trace_streamer/src/filter/config_filter.cpp b/trace_streamer/src/filter/config_filter.cpp index dd03a20c..ad7035db 100644 --- a/trace_streamer/src/filter/config_filter.cpp +++ b/trace_streamer/src/filter/config_filter.cpp @@ -153,7 +153,7 @@ SwitchConfig::SwitchConfig(const json &config) binderRunnableConfigEnabled_ = config.value("BinderRunnable", 0) == 1; HMKernelTraceEnabled_ = config.value("HMKernel", 0) == 1; rawTraceCutStartTsEnabled_ = config.value("RawTraceCutStartTs", 0) == 1; - ffrtConvertEnabled_ = config.value("FFRTConvert", 0) == 1; + ffrtConvertEnabled_ = config.value("FfrtConvert", 0) == 1; std::string syscalls = config.value("System Calls", ""); UpdateSyscallsTsSet(syscalls); TS_LOGI( -- Gitee From 2f3689550f7344d843551a5e55b9f2c61e25e382 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 13 Jun 2025 09:53:38 +0800 Subject: [PATCH 32/51] =?UTF-8?q?fix:statstics=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- .../trace/sheet/native-memory/TabPaneNMStatstics.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts index 212d6bd7..83ea5de7 100644 --- a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts @@ -76,11 +76,6 @@ export class TabPaneNMStatstics extends BaseElement { queryData(nativeStatisticsParam: SelectionParam): void { Promise.all([ queryNativeHookStatistics(nativeStatisticsParam.leftNs, nativeStatisticsParam.rightNs, this.currentSelectIPid), - queryNativeHookStatisticsSubType( - nativeStatisticsParam.leftNs, - nativeStatisticsParam.rightNs, - this.currentSelectIPid - ), queryNativeHookStatisticsMalloc( nativeStatisticsParam.leftNs, nativeStatisticsParam.rightNs, @@ -94,7 +89,7 @@ export class TabPaneNMStatstics extends BaseElement { let index3 = nativeStatisticsParam.nativeMemory.indexOf(this.nativeType[2]); this.setMemoryTypeData(nativeStatisticsParam, values[0], arr); if (index1 !== -1 || index3 !== -1) { - this.setSubTypeTableData(values[1], arr); + this.setSubTypeTableData([values[0][1]], arr); } let type = 0; if (index1 !== -1 || (index2 !== -1 && index3 !== -1)) { @@ -102,7 +97,7 @@ export class TabPaneNMStatstics extends BaseElement { } else { type = index2 !== -1 ? 1 : 2; } - this.setMallocTableData(values[2], arr, type); + this.setMallocTableData(values[1], arr, type); this.nativeStatisticsSource = arr; this.sortByColumn(this.sortColumn, this.sortType); }); -- Gitee From 6477b60ed80c9625e5741091ea0ed88174d62768 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 13 Jun 2025 11:36:25 +0800 Subject: [PATCH 33/51] =?UTF-8?q?feat:=E6=8F=92=E4=BB=B6=E6=8A=93=E5=8F=96?= =?UTF-8?q?HisystemEvent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- ide/src/trace/component/SpRecordTrace.ts | 3 ++ .../trace/component/setting/SpHisysEvent.ts | 29 +++++++++++++++---- ide/src/webSocket/Constants.ts | 1 + 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/ide/src/trace/component/SpRecordTrace.ts b/ide/src/trace/component/SpRecordTrace.ts index 457e57ca..1eb50883 100644 --- a/ide/src/trace/component/SpRecordTrace.ts +++ b/ide/src/trace/component/SpRecordTrace.ts @@ -138,6 +138,7 @@ export class SpRecordTrace extends BaseElement { public static usbGetEvent: string; public static usbGetApp: string; private static usbGetVersion: string; + public static usbGetHisystem: string; static snapShotList: Array = []; static snapShotDuration: number = 0; static isSnapShotCapture: boolean = false; @@ -883,6 +884,8 @@ export class SpRecordTrace extends BaseElement { SpRecordTrace.usbGetApp = jsonRes.resultMessage; } else if (cmd === TypeConstants.USB_GET_VERSION) { SpRecordTrace.usbGetVersion = jsonRes.resultMessage; + } else if (cmd === TypeConstants.USB_GET_HISYSTEM) { + SpRecordTrace.usbGetHisystem = jsonRes.resultMessage; } }; diff --git a/ide/src/trace/component/setting/SpHisysEvent.ts b/ide/src/trace/component/setting/SpHisysEvent.ts index 9cb549b5..1bddae38 100644 --- a/ide/src/trace/component/setting/SpHisysEvent.ts +++ b/ide/src/trace/component/setting/SpHisysEvent.ts @@ -22,6 +22,8 @@ import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager'; import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect'; import { SpHiSysEventHtml } from './SpHisysEvent.html'; import { LitSelectV } from '../../../base-ui/select/LitSelectV'; +import { WebSocketManager } from '../../../webSocket/WebSocketManager'; +import { TypeConstants } from '../../../webSocket/Constants'; @element('sp-hisys-event') export class SpHisysEvent extends BaseElement { @@ -99,11 +101,11 @@ export class SpHisysEvent extends BaseElement { if (SpRecordTrace.serialNumber === '') { this.domainInputEL!.dataSource([], ''); } else { - HdcDeviceManager.fileRecv(this.sysEventConfigPath, () => { }).then((pullRes) => { - pullRes.arrayBuffer().then((buffer) => { - if (buffer.byteLength > 0) { - let dec = new TextDecoder(); - this.eventConfig = JSON.parse(dec.decode(buffer)); + if (SpRecordTrace.useExtend) { + WebSocketManager.getInstance()!.sendMessage(TypeConstants.USB_TYPE, TypeConstants.USB_GET_HISYSTEM, new TextEncoder().encode(SpRecordTrace.serialNumber)); + setTimeout(() => { + if (SpRecordTrace.usbGetHisystem) { + this.eventConfig = JSON.parse(SpRecordTrace.usbGetHisystem); let domainList = Object.keys(this.eventConfig!); if (domainList.length > 0) { this.domainInputEL!.dataSource(domainList, 'ALL-Domain', true); @@ -111,8 +113,23 @@ export class SpHisysEvent extends BaseElement { this.domainInputEL!.dataSource([], ''); } } + }, 1000); + } else { + HdcDeviceManager.fileRecv(this.sysEventConfigPath, () => { }).then((pullRes) => { + pullRes.arrayBuffer().then((buffer) => { + if (buffer.byteLength > 0) { + let dec = new TextDecoder(); + this.eventConfig = JSON.parse(dec.decode(buffer)); + let domainList = Object.keys(this.eventConfig!); + if (domainList.length > 0) { + this.domainInputEL!.dataSource(domainList, 'ALL-Domain', true); + } else { + this.domainInputEL!.dataSource([], ''); + } + } + }); }); - }); + } } this.domainInputEl!.removeAttribute('readonly'); } else { diff --git a/ide/src/webSocket/Constants.ts b/ide/src/webSocket/Constants.ts index 491dd660..b4eb937f 100644 --- a/ide/src/webSocket/Constants.ts +++ b/ide/src/webSocket/Constants.ts @@ -47,4 +47,5 @@ export class TypeConstants { static USB_GET_EVENT = 4; static USB_GET_APP = 5; static USB_GET_VERSION = 6; + static USB_GET_HISYSTEM = 7; } \ No newline at end of file -- Gitee From d59a23c963c74b550fdab2d12c5b7974dba981f6 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Fri, 13 Jun 2025 10:04:24 +0800 Subject: [PATCH 34/51] Fix hiviewdfx faultloggerd for smartfd.Fix ffrtConvertEnabled_ for FfrtConvert. Signed-off-by: JustinYT --- .../patch_hiperf/hiviewdfx_faultloggerd.patch | 99 ++++++------------- trace_streamer/src/filter/BUILD.gn | 1 + trace_streamer/src/filter/config_filter.cpp | 2 +- 3 files changed, 34 insertions(+), 68 deletions(-) diff --git a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch index 56803cb2..8fd8419f 100644 --- a/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch +++ b/trace_streamer/prebuilts/patch_hiperf/hiviewdfx_faultloggerd.patch @@ -1,21 +1,36 @@ -diff --git a/common/dfxutil/dfx_util.cpp b/common/dfxutil/dfx_util.cpp -index a90f4303..9429fd43 100644 ---- a/common/dfxutil/dfx_util.cpp -+++ b/common/dfxutil/dfx_util.cpp -@@ -229,7 +229,11 @@ bool ReadFdToString(int fd, std::string& content) - void CloseFd(int &fd) - { - if (fd > 0) { +diff --git a/common/dfxutil/smart_fd.h b/common/dfxutil/smart_fd.h +index fd5e838..858ae73 100644 +--- a/common/dfxutil/smart_fd.h ++++ b/common/dfxutil/smart_fd.h +@@ -28,9 +28,11 @@ public: + SmartFd() = default; + explicit SmartFd(int fd, bool fdsan = true) : fd_(fd), fdsan_(fdsan) + { ++#if is_ohos + if (fd_ >= 0 && fdsan_) { + fdsan_exchange_owner_tag(fd_, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN)); + } ++#endif + } + + ~SmartFd() +@@ -85,11 +87,14 @@ private: + if (fd_ < 0) { + return; + } +#if is_ohos - fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN)); + if (fdsan_) { + fdsan_close_with_tag(fd_, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN)); + return; + } +#else -+ close(fd); + close(fd_); +#endif - fd = -1; } - } + + int fd_{-1}; diff --git a/common/dfxutil/string_view_util.h b/common/dfxutil/string_view_util.h -index b44a59ea..7dbd3568 100644 +index b44a59e..7dbd356 100644 --- a/common/dfxutil/string_view_util.h +++ b/common/dfxutil/string_view_util.h @@ -24,6 +24,24 @@ @@ -122,7 +137,7 @@ index b44a59ea..7dbd3568 100644 } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/common/byte_order.h b/interfaces/common/byte_order.h -index 3c40993e..a55d9db0 100644 +index 3c40993..a55d9db 100644 --- a/interfaces/common/byte_order.h +++ b/interfaces/common/byte_order.h @@ -16,7 +16,7 @@ @@ -135,7 +150,7 @@ index 3c40993e..a55d9db0 100644 #define UNWIND_BIG_ENDIAN 4321 #define UNWIND_BYTE_ORDER -1 // Unknown diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_define.h b/interfaces/innerkits/unwinder/include/dfx_elf_define.h -index 6bc93949..a71d76b5 100644 +index 6bc9394..a71d76b 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_define.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_define.h @@ -17,7 +17,7 @@ @@ -148,7 +163,7 @@ index 6bc93949..a71d76b5 100644 #include #endif diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h -index b4c84437..86a4bdd1 100644 +index b4c8443..86a4bdd 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h @@ -16,7 +16,7 @@ @@ -161,7 +176,7 @@ index b4c84437..86a4bdd1 100644 #else #include diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp -index 9398e59a..79d230e0 100644 +index 9398e59..79d230e 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp +++ b/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp @@ -1,749 +1,749 @@ @@ -1663,53 +1678,3 @@ index 9398e59a..79d230e0 100644 +} +} // namespace HiviewDFX +} // namespace OHOS -diff --git a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp -index cbe67062..52ced531 100644 ---- a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp -+++ b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp -@@ -151,8 +151,10 @@ std::shared_ptr RegularElfFactory::Create() - DFXLOGE("Failed to open file: %{public}s, errno(%{public}d)", filePath_.c_str(), errno); - return regularElf; - } -+#if is_ohos - uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN); - fdsan_exchange_owner_tag(fd, 0, ownerTag); -+#endif - do { - auto size = static_cast(GetFileSize(fd)); - auto mMap = std::make_shared(); -@@ -162,7 +164,11 @@ std::shared_ptr RegularElfFactory::Create() - } - regularElf->SetMmap(mMap); - } while (false); -+#if is_ohos - fdsan_close_with_tag(fd, ownerTag); -+#else -+ close(fd); -+#endif - return regularElf; - } - -@@ -215,8 +221,10 @@ std::shared_ptr CompressHapElfFactory::Create() - DFXLOGE("Failed to open hap file, errno(%{public}d)", errno); - return nullptr; - } -+#if is_ohos - uint64_t ownerTag = fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, LOG_DOMAIN); - fdsan_exchange_owner_tag(fd, 0, ownerTag); -+#endif - std::shared_ptr compressHapElf = nullptr; - do { - size_t elfSize = 0; -@@ -237,7 +245,11 @@ std::shared_ptr CompressHapElfFactory::Create() - break; - } - } while (false); -+#if is_ohos - fdsan_close_with_tag(fd, ownerTag); -+#else -+ close(fd); -+#endif - return compressHapElf; - } - diff --git a/trace_streamer/src/filter/BUILD.gn b/trace_streamer/src/filter/BUILD.gn index 33a4036c..cb8a9f50 100644 --- a/trace_streamer/src/filter/BUILD.gn +++ b/trace_streamer/src/filter/BUILD.gn @@ -50,6 +50,7 @@ config("filter_cfg") { "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/nonlinux", "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/common", "${THIRD_PARTY}/hiviewdfx/faultloggerd/common/dfxutil", + "${THIRD_PARTY}/hiviewdfx/faultloggerd/common/dfxlog", "${PERF_DIR}/hiperf/include/nonlinux", "${THIRD_PARTY}/libbpf/include/uapi", "${THIRD_PARTY}/bounds_checking_function/include", diff --git a/trace_streamer/src/filter/config_filter.cpp b/trace_streamer/src/filter/config_filter.cpp index dd03a20c..ad7035db 100644 --- a/trace_streamer/src/filter/config_filter.cpp +++ b/trace_streamer/src/filter/config_filter.cpp @@ -153,7 +153,7 @@ SwitchConfig::SwitchConfig(const json &config) binderRunnableConfigEnabled_ = config.value("BinderRunnable", 0) == 1; HMKernelTraceEnabled_ = config.value("HMKernel", 0) == 1; rawTraceCutStartTsEnabled_ = config.value("RawTraceCutStartTs", 0) == 1; - ffrtConvertEnabled_ = config.value("FFRTConvert", 0) == 1; + ffrtConvertEnabled_ = config.value("FfrtConvert", 0) == 1; std::string syscalls = config.value("System Calls", ""); UpdateSyscallsTsSet(syscalls); TS_LOGI( -- Gitee From f724707895d9468f076cffd4e645e328d145c981 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Sat, 14 Jun 2025 19:21:01 +0800 Subject: [PATCH 35/51] =?UTF-8?q?fix:Host=E5=B7=A5=E5=85=B7=E9=9D=99?= =?UTF-8?q?=E6=80=81=E8=B5=84=E6=BA=90&=E6=8E=A5=E5=8F=A3=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E8=B7=AF=E5=BE=84=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/server/main.go | 2 +- ide/server/server-config.json | 2 +- ide/src/doc/quickstart_extensions.html | 3 +- ide/src/hdc/hdcclient/HdcClient.ts | 4 +- .../statistics/util/SpStatisticsHttpUtil.ts | 54 +-------- ide/src/trace/SpApplication.ts | 28 +++-- ide/src/trace/SpApplicationPublicFunc.ts | 2 +- ide/src/trace/component/SpHelp.ts | 12 +- ide/src/trace/component/SpRecordTrace.ts | 103 +++++++++++------- ide/src/trace/component/SpSystemTrace.init.ts | 2 +- .../trace/component/setting/SpSdkConfig.ts | 4 +- .../component/trace/base/TraceRowConfig.ts | 2 +- .../trace/sheet/hiperf/TabPanePerfAnalysis.ts | 2 +- .../trace/sheet/hiperf/TabPerfFuncAsm.html.ts | 6 +- .../logic-worker/ProcedureLogicWorkerPerf.ts | 3 + ide/src/webSocket/WebSocketManager.ts | 53 ++++----- 16 files changed, 126 insertions(+), 156 deletions(-) diff --git a/ide/server/main.go b/ide/server/main.go index 530ff115..772b1c4a 100644 --- a/ide/server/main.go +++ b/ide/server/main.go @@ -173,7 +173,7 @@ func main() { mime.TypeByExtension(".js") mime.AddExtensionType(".js", "application/javascript") log.Println(mime.TypeByExtension(".js")) - mux.HandleFunc("/logger", consoleHandler) + mux.HandleFunc("/application/logger", consoleHandler) mux.Handle("/application/upload/", http.StripPrefix("/application/upload/", http.FileServer(http.Dir(filepath.FromSlash(exPath+"/upload"))))) mux.HandleFunc("/application/download-file", downloadHandler) mux.HandleFunc("/application/serverInfo", serverInfo) diff --git a/ide/server/server-config.json b/ide/server/server-config.json index 637b4034..0d231c8a 100644 --- a/ide/server/server-config.json +++ b/ide/server/server-config.json @@ -1,4 +1,4 @@ { - "ServeInfo": "127.0.0.1:9100/statistics", + "ServeInfo": "smartperf.rnd.huawei.com/statistics", "MsgPublishFile": "" } \ No newline at end of file diff --git a/ide/src/doc/quickstart_extensions.html b/ide/src/doc/quickstart_extensions.html index c39d01ea..063f237e 100644 --- a/ide/src/doc/quickstart_extensions.html +++ b/ide/src/doc/quickstart_extensions.html @@ -840,8 +840,7 @@ targetElement.scrollIntoView({ behavior: 'smooth' }); } // 假设这是你的文件的 URL - const fileUrl = `https://${window.location.host.split(':')[0]}:${window.location.port - }/application/extend/hi-smart-perf-host-extend.zip`; + const fileUrl = `../extend/hi-smart-perf-host-extend.zip`; const fileName = 'hi-smart-perf-host-extend'; // 创建一个隐藏的 a 元素 const a = document.createElement('a'); diff --git a/ide/src/hdc/hdcclient/HdcClient.ts b/ide/src/hdc/hdcclient/HdcClient.ts index 5393d55c..40ca22cd 100644 --- a/ide/src/hdc/hdcclient/HdcClient.ts +++ b/ide/src/hdc/hdcclient/HdcClient.ts @@ -78,7 +78,7 @@ export class HdcClient implements DataListener { continue; case AuthType.AUTH_SIGNATURE: const hdcMsgUrl = this.isSigna ? 'signatureHdcMsg' : 'encryptHdcMsg'; - const response = await fetch(`${window.location.origin}/application/${hdcMsgUrl}?message=` + returnBuf); + const response = await fetch(`${window.location.origin}${window.location.pathname}${hdcMsgUrl}?message=` + returnBuf); const dataBody = await response.json(); let signatureHdcMsg = ''; if (dataBody.success) { @@ -95,7 +95,7 @@ export class HdcClient implements DataListener { } else { this.isSigna = false; } - const responsePub = await fetch(`${window.location.origin}/application/hdcPublicKey`); + const responsePub = await fetch(`${window.location.origin}${window.location.pathname}hdcPublicKey`); const data = await responsePub.json(); const publicKey = data.success && (`smartPerf-Host` + String.fromCharCode(12) + data.data.publicKey); await this.handShakeConnect(AuthType.AUTH_PUBLICKEY, publicKey); diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts index 0d9357cc..36e96531 100644 --- a/ide/src/statistics/util/SpStatisticsHttpUtil.ts +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -22,7 +22,6 @@ export class SpStatisticsHttpUtil { static timeDiff: number = 0; static retryCount: number = 0; static retryMaxCount: number = 5; - static pauseRetry: boolean = false; static retryRestTimeOut: boolean = false; static recordPlugin: Array = []; static controllersMap: Map = new Map(); @@ -30,42 +29,16 @@ export class SpStatisticsHttpUtil { static initStatisticsServerConfig(): void { if (SpStatisticsHttpUtil.requestServerInfo === '') { - SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); + return; } if (SpStatisticsHttpUtil.serverTime === 0) { SpStatisticsHttpUtil.getServerTime(); } } - static getRequestServerInfo(): string { - try { - let req = new XMLHttpRequest(); - req.onreadystatechange = (): void => { - if (req.readyState === 4 && req.status === 200) { - let requestInfo = req.getResponseHeader('request_info'); - if (requestInfo && requestInfo.length > 0) { - SpStatisticsHttpUtil.requestServerInfo = requestInfo; - } - } - }; - req.open( - 'GET', - `${window.location.protocol}//${window.location.host.split(':')[0]}:${window.location.port - }/application/serverInfo`, - true - ); - req.send(null); - } catch { - warn('Connect Server Failed'); - } - return ''; - } static getServerTime(): void { if (SpStatisticsHttpUtil.requestServerInfo === '') { - SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); - } - if (SpStatisticsHttpUtil.pauseRetry) { return; } fetch(`https://${SpStatisticsHttpUtil.requestServerInfo}/serverTime`) @@ -77,26 +50,9 @@ export class SpStatisticsHttpUtil { } }); }) - .catch((e) => { - this.handleRequestException(); - }); + .catch((e) => {}); } - private static handleRequestException(): void { - if (SpStatisticsHttpUtil.retryCount >= SpStatisticsHttpUtil.retryMaxCount) { - SpStatisticsHttpUtil.pauseRetry = true; - if (SpStatisticsHttpUtil.retryRestTimeOut) { - return; - } - SpStatisticsHttpUtil.retryRestTimeOut = true; - setTimeout(() => { - SpStatisticsHttpUtil.retryCount = 0; - SpStatisticsHttpUtil.pauseRetry = false; - SpStatisticsHttpUtil.retryRestTimeOut = false; - }, 600000); - } - ++SpStatisticsHttpUtil.retryCount; - } static addUserVisitAction(requestUrl: string): void { // @ts-ignore @@ -104,9 +60,6 @@ export class SpStatisticsHttpUtil { return; } if (SpStatisticsHttpUtil.requestServerInfo === '') { - SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); - } - if (SpStatisticsHttpUtil.pauseRetry) { return; } let visitId = 0; @@ -147,9 +100,6 @@ export class SpStatisticsHttpUtil { return; } if (SpStatisticsHttpUtil.requestServerInfo === '') { - SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); - } - if (SpStatisticsHttpUtil.pauseRetry) { return; } requestBody.ts = SpStatisticsHttpUtil.getCorrectRequestTime(); diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index 4b5e2e10..bae7d464 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -281,8 +281,16 @@ export class SpApplication extends BaseElement { } initPlugin(): void { - SpStatisticsHttpUtil.initStatisticsServerConfig(); - SpStatisticsHttpUtil.addUserVisitAction('visit'); + let url = `${window.location.protocol}//${window.location.host.split(':')[0]}:${window.location.port + }${window.location.pathname}serverInfo`; + fetch(url, { method: 'GET' }).then((res) => { + if (res.headers) { + const headers = res.headers; + SpStatisticsHttpUtil.requestServerInfo = headers.get('request_info')!; + SpStatisticsHttpUtil.initStatisticsServerConfig(); + SpStatisticsHttpUtil.addUserVisitAction('visit'); + } + }) LongTraceDBUtils.getInstance().createDBAndTable().then(); } @@ -1174,8 +1182,8 @@ export class SpApplication extends BaseElement { traceType = 'sqlite'; } Promise.all([threadPool.init(traceType), threadPool2.init(traceType)]).then(() => { - let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; - let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/config/config.json`; + let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}wasm.json`; + let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}config/config.json`; Promise.all([file1.arrayBuffer(), file2.arrayBuffer()]).then((bufArr) => { this.litSearch!.setPercent('ArrayBuffer loaded ', 2); SpApplication.loadingProgress = 0; @@ -1240,15 +1248,15 @@ export class SpApplication extends BaseElement { reader.onloadend = (ev): void => { info('read file onloadend'); this.litSearch!.setPercent('ArrayBuffer loaded ', 2); - let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; - let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/config/config.json`; + let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}wasm.json`; + let configUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}config/config.json`; SpApplication.loadingProgress = 0; SpApplication.progressStep = 3; let data = this.markPositionHandler(reader.result as ArrayBuffer); info('initData start Parse Data'); this.spSystemTrace!.loadDatabaseArrayBuffer( data, - wasmUrl,configUrl, + wasmUrl, configUrl, (command: string, _: number) => this.setProgress(command), false, completeHandler @@ -1761,7 +1769,7 @@ export class SpApplication extends BaseElement { let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); querySelectors.forEach((item) => { if (item.getAttribute('title') === 'Convert to .systrace') { - if(fileName.indexOf('.htrace')>0){ + if (fileName.indexOf('.htrace') > 0) { SpStatisticsHttpUtil.addOrdinaryVisitAction({ event: 'convert_systrace', action: 'convert_systrace', @@ -2556,7 +2564,7 @@ export class SpApplication extends BaseElement { openUrl(arrayBuf, fileName, showFileName, arrayBuf.byteLength); }); } else { - let api = `${window.location.origin}/application/download-file`; + let api = `${window.location.origin}${window.location.pathname}download-file`; fetch(api, { method: 'POST', headers: { @@ -2578,7 +2586,7 @@ export class SpApplication extends BaseElement { } }) .catch((e) => { - let api = `${window.location.origin}/application/download-file`; + let api = `${window.location.origin}${window.location.pathname}download-file`; fetch(api, { method: 'POST', headers: { diff --git a/ide/src/trace/SpApplicationPublicFunc.ts b/ide/src/trace/SpApplicationPublicFunc.ts index 6c366a72..73c915d5 100644 --- a/ide/src/trace/SpApplicationPublicFunc.ts +++ b/ide/src/trace/SpApplicationPublicFunc.ts @@ -471,7 +471,7 @@ export function clearTraceFileCache(): void { } export function postLog(filename: string, fileSize: string): void { - fetch(`https://${window.location.host.split(':')[0]}:${window.location.port}/logger`, { + fetch(`https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}logger`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/ide/src/trace/component/SpHelp.ts b/ide/src/trace/component/SpHelp.ts index 3aca9c13..4cd235c6 100644 --- a/ide/src/trace/component/SpHelp.ts +++ b/ide/src/trace/component/SpHelp.ts @@ -39,7 +39,7 @@ export class SpHelp extends BaseElement { } this.helpFile!.innerHTML = '`; this.navbarInit(helpDocDetail!.name); @@ -269,13 +269,13 @@ export class SpHelp extends BaseElement { event: event, action: 'help_doc', }); - that.helpFile!.innerHTML = ``; + that.helpFile!.innerHTML = ``; this.navbarInit(docName); this.changeItemURL(index!); } private navbarInit(docName: string): void { - fetch(`/application/doc/${docName}.html`) + fetch(`doc/${docName}.html`) .then(response => response.text()) .then(htmlString => { const parser = new DOMParser(); @@ -303,7 +303,7 @@ export class SpHelp extends BaseElement { navLink.closest('li')!.classList.add('active'); let targetId = navLink.id; e.preventDefault(); - this.helpFile!.innerHTML = ``; + this.helpFile!.innerHTML = ``; }); }); @@ -312,7 +312,7 @@ export class SpHelp extends BaseElement { navLinks.forEach((navLink) => { navLink.closest('li')?.classList.remove('active'); }); - this.helpFile!.innerHTML = ``; + this.helpFile!.innerHTML = ``; }); }) diff --git a/ide/src/trace/component/SpRecordTrace.ts b/ide/src/trace/component/SpRecordTrace.ts index 457e57ca..af564dc2 100644 --- a/ide/src/trace/component/SpRecordTrace.ts +++ b/ide/src/trace/component/SpRecordTrace.ts @@ -114,6 +114,7 @@ export class SpRecordTrace extends BaseElement { private spWebShell: SpWebHdcShell | undefined; private menuGroup: LitMainMenuGroup | undefined | null; private appContent: HTMLElement | undefined | null; + private optionNum: number = 0; private record = 'Record'; private stop = 'StopRecord'; private nowChildItem: HTMLElement | undefined; @@ -597,7 +598,7 @@ export class SpRecordTrace extends BaseElement { this.progressEL!.loading = false;// @ts-ignore let errorMsg = new TextDecoder().decode(result); this.useExtentTip!.style.display = 'block'; - let urlAsciiArr = [104,116,116,112,115,58,47,47,119,105,107,105,46,104,117,97,119,101,105,46,99,111,109,47,100,111,109,97,105,110,115,47,55,54,57,49,49,47,119,105,107,105,47,49,50,53,52,56,48,47,87,73,75,73,50,48,50,53,48,49,49,54,53,55,53,48,52,53,52]; + let urlAsciiArr = [104, 116, 116, 112, 115, 58, 47, 47, 119, 105, 107, 105, 46, 104, 117, 97, 119, 101, 105, 46, 99, 111, 109, 47, 100, 111, 109, 97, 105, 110, 115, 47, 55, 54, 57, 49, 49, 47, 119, 105, 107, 105, 47, 49, 50, 53, 52, 56, 48, 47, 87, 73, 75, 73, 50, 48, 50, 53, 48, 49, 49, 54, 53, 55, 53, 48, 52, 53, 52]; let exceptGuid = String.fromCodePoint(...urlAsciiArr); this.useExtentTip!.innerHTML = `抓取trace异常:${errorMsg} 可根据[常见异常处理]解决异常`; this.refreshDisableStyle(false, false); @@ -803,6 +804,35 @@ export class SpRecordTrace extends BaseElement { }; }; + usbGetVersion(dev: string) { + let option = document.createElement('option'); + option.className = 'select'; + this.optionNum++; + // @ts-ignore + option.value = dev; + // @ts-ignore + option.textContent = dev.toString(); + this.deviceSelect!.appendChild(option); + if (dev.toString() === SpRecordTrace.serialNumber || SpRecordTrace.serialNumber === '') { + SpRecordTrace.serialNumber = dev; + option.selected = true; + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + this.cancelButton!.hidden = true; + this.devicePrompt!.innerText = ''; + this.hintEl!.textContent = ''; + // @ts-ignore + WebSocketManager.getInstance()!.sendMessage(TypeConstants.USB_TYPE, TypeConstants.USB_GET_VERSION, new TextEncoder().encode(dev)); + setTimeout(() => { + if (SpRecordTrace.usbGetVersion) { + SpRecordTrace.selectVersion = this.getDeviceVersion(SpRecordTrace.usbGetVersion); + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + this.nativeMemoryHideBySelectVersion(); + } + }, 1000); + } + } + webSocketCallBackasync = (cmd: number, result: Uint8Array): void => { const decoder = new TextDecoder(); const jsonString = decoder.decode(result); @@ -812,20 +842,37 @@ export class SpRecordTrace extends BaseElement { HdcDeviceManager.findDevice().then((usbDevices): void => { SpRecordTrace.serialNumber = usbDevices.serialNumber; this.usbSerialNum = jsonRes.resultMessage; - let optionNum = 0; - if (this.usbSerialNum.length === 1 && this.usbSerialNum[0].includes('Empty')) { + this.optionNum = 0; + if (this.usbSerialNum.length === 1) { + if (this.usbSerialNum[0].includes('Empty')) { + this.usbSerialNum.shift(); + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + this.cancelButton!.hidden = true; + this.devicePrompt!.innerText = 'Device not connected'; + this.deviceSelect!.style!.border = '2px solid red'; + setTimeout(() => { + this.deviceSelect!.style!.border = '1px solid #4D4D4D'; + }, 3000); + this.useExtentTip!.style.display = 'block'; + this.useExtentTip!.innerHTML = '手机连接有问题,请重新插拔一下手机,或者请使用系统管理员权限打开cmd窗口,并执行hdc shell'; + return; + }else{ + this.usbGetVersion(this.usbSerialNum[0]); + } + }else if(this.usbSerialNum.length > 1 && usbDevices.serialNumber === ''){ this.usbSerialNum.shift(); - this.recordButton!.hidden = true; - this.disconnectButton!.hidden = true; - this.cancelButton!.hidden = true; - this.devicePrompt!.innerText = 'Device not connected'; - this.deviceSelect!.style!.border = '2px solid red'; - setTimeout(() => { - this.deviceSelect!.style!.border = '1px solid #4D4D4D'; - }, 3000); - this.useExtentTip!.style.display = 'block'; - this.useExtentTip!.innerHTML = '手机连接有问题,请重新插拔一下手机,或者请使用系统管理员权限打开cmd窗口,并执行hdc shell'; - return; + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + this.cancelButton!.hidden = true; + this.devicePrompt!.innerText = 'Device not connected'; + this.deviceSelect!.style!.border = '2px solid red'; + setTimeout(() => { + this.deviceSelect!.style!.border = '1px solid #4D4D4D'; + }, 3000); + this.useExtentTip!.style.display = 'block'; + this.useExtentTip!.innerHTML = '加密设备仅限连接一台'; + return; } // @ts-ignore while (this.deviceSelect!.firstChild) { @@ -833,33 +880,9 @@ export class SpRecordTrace extends BaseElement { } for (let len = 0; len < this.usbSerialNum.length; len++) { let dev = this.usbSerialNum[len]; - let option = document.createElement('option'); - option.className = 'select'; - optionNum++; - // @ts-ignore - option.value = dev; - // @ts-ignore - option.textContent = dev.toString(); - this.deviceSelect!.appendChild(option); - if (dev.toString() === SpRecordTrace.serialNumber) { - option.selected = true; - this.recordButton!.hidden = false; - this.disconnectButton!.hidden = false; - this.cancelButton!.hidden = true; - this.devicePrompt!.innerText = ''; - this.hintEl!.textContent = ''; - // @ts-ignore - WebSocketManager.getInstance()!.sendMessage(TypeConstants.USB_TYPE, TypeConstants.USB_GET_VERSION, new TextEncoder().encode(dev)); - setTimeout(() => { - if (SpRecordTrace.usbGetVersion) { - SpRecordTrace.selectVersion = this.getDeviceVersion(SpRecordTrace.usbGetVersion); - this.setDeviceVersionSelect(SpRecordTrace.selectVersion); - this.nativeMemoryHideBySelectVersion(); - } - }, 1000); - } + this.usbGetVersion(dev); } - if (!optionNum) { + if (!this.optionNum) { this.deviceSelect!.style!.border = '2px solid red'; setTimeout(() => { this.deviceSelect!.style!.border = '1px solid #4D4D4D'; diff --git a/ide/src/trace/component/SpSystemTrace.init.ts b/ide/src/trace/component/SpSystemTrace.init.ts index 75b7b3ea..32477920 100644 --- a/ide/src/trace/component/SpSystemTrace.init.ts +++ b/ide/src/trace/component/SpSystemTrace.init.ts @@ -1330,7 +1330,7 @@ export async function spSystemTraceInit( SpStatisticsHttpUtil.recordPluginUsage(); // trace文件加载完毕,将动效json文件读取并存入缓存 let funDetailUrl = `https://${window.location.host.split(':')[0]}:${window.location.port - }/application/doc/funDetail.json`; + }${window.location.pathname}doc/funDetail.json`; let xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象 xhr.open('GET', funDetailUrl); diff --git a/ide/src/trace/component/setting/SpSdkConfig.ts b/ide/src/trace/component/setting/SpSdkConfig.ts index a8426c1a..868475ee 100644 --- a/ide/src/trace/component/setting/SpSdkConfig.ts +++ b/ide/src/trace/component/setting/SpSdkConfig.ts @@ -149,9 +149,9 @@ export class SpSdkConfig extends BaseElement { private initSdkWasm(): void { try { let spApplication = document.querySelector('sp-application'); - let wasmJsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; + let wasmJsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}wasm.json`; if (spApplication!.hasAttribute('vs')) { - wasmJsonUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}/wasm.json`; + wasmJsonUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}${window.location.pathname}/wasm.json`; } fetch(wasmJsonUrl) .then((res): void => { diff --git a/ide/src/trace/component/trace/base/TraceRowConfig.ts b/ide/src/trace/component/trace/base/TraceRowConfig.ts index 904bef12..b43e77e9 100644 --- a/ide/src/trace/component/trace/base/TraceRowConfig.ts +++ b/ide/src/trace/component/trace/base/TraceRowConfig.ts @@ -441,7 +441,7 @@ export class TraceRowConfig extends BaseElement { private initSwitchClickListener(): void { let jsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port - }/application/trace/config/custom_temp_config.json`; + }${window.location.pathname}trace/config/custom_temp_config.json`; this.switchButton!.addEventListener('click', () => { // @ts-ignore this.inputElement?.value = ''; diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts index ba92636a..57993a75 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -694,7 +694,7 @@ export class TabPanePerfAnalysis extends BaseElement { encodedData = textEncoder.encode(dataString); WebSocketManager.getInstance()?.registerMessageListener(TypeConstants.DISASSEMBLY_TYPE, this.callback, () => { }, true); WebSocketManager.getInstance()?.sendMessage(TypeConstants.DISASSEMBLY_TYPE, Constants.DISASSEMBLY_QUERY_ELF_CMD, encodedData); - if (WebSocketManager.disaStatus !== 'ready') { + if (WebSocketManager.getInstance()!.status !== 'ready') { // @ts-ignore this.perfAnalysisHeadTips?.innerHTML = 'Request timed out.Install the extended service according to the help document.'; return; 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 f7b7de69..83e8a071 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfFuncAsm.html.ts @@ -74,9 +74,9 @@ export const TabPerfFuncAsmHtml = ` - - - + + +
diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 55eec1ba..814c862e 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -1449,6 +1449,9 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { combineCallChainForAnalysis(obj?: unknown): PerfAnalysisSample[] { let sampleCallChainList: Array = []; for (let sample of this.samplesData) { + if (!this.callChainData[sample.sampleId]) { + continue; + } let callChains = [...this.callChainData[sample.sampleId]]; const lastCallChain = callChains[callChains.length - 1]; const threadName = this.threadData[sample.tid].threadName || 'Thread'; diff --git a/ide/src/webSocket/WebSocketManager.ts b/ide/src/webSocket/WebSocketManager.ts index 9318f1fa..b92eaa3c 100644 --- a/ide/src/webSocket/WebSocketManager.ts +++ b/ide/src/webSocket/WebSocketManager.ts @@ -38,11 +38,10 @@ export class WebSocketManager { private sessionId: number | null | undefined; private session: bigint | null | undefined; private heartbeatInterval: number | null | undefined; - private status: string = GetStatuses.UNCONNECTED; + public status: string = GetStatuses.UNCONNECTED; private cacheInfo: Map = new Map(); private reconnect: number = -1; private connectStatus: HTMLElement | null | undefined; - static disaStatus: string = GetStatuses.UNCONNECTED; constructor() { if (WebSocketManager.instance) { @@ -58,8 +57,6 @@ export class WebSocketManager { this.connectStatus = document.querySelector("body > sp-application").shadowRoot.querySelector("#main-menu").shadowRoot.querySelector("div.bottom > div.extend_connect"); this.websocket = new WebSocket(this.url); this.websocket.binaryType = 'arraybuffer'; - // @ts-ignore - setInterval(this.checkConnectionStatus(this.websocket), 5000); this.websocket.onopen = (): void => { this.status = GetStatuses.CONNECTED; // 设置心跳定时器 @@ -80,11 +77,12 @@ export class WebSocketManager { this.websocket.onerror = (error): void => { console.error('error:', error); + this.extendTips(false); }; this.websocket.onclose = (event): void => { this.status = GetStatuses.UNCONNECTED; - this.checkConnectionStatus(this.websocket); + this.extendTips(false); this.finalStatus(); //初始化标志位 this.initLoginInfo(); @@ -92,19 +90,6 @@ export class WebSocketManager { }; } - /** - * 实时监听websockets连接状态 - */ - checkConnectionStatus(websocket: WebSocket | null | undefined) { - // @ts-ignore - if (websocket?.readyState === websocket?.OPEN) { - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'green'; - } else { - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'red'; - } - } /** * 接收webSocket返回的buffer数据 @@ -117,9 +102,22 @@ export class WebSocketManager { } else if (decode.type === TypeConstants.UPDATE_TYPE) {// 升级 this.updateMessage(decode); } else {// type其他 + this.businessMessage(decode); + } + } + + // 扩展服务连接状态提示 + extendTips(flag: boolean): void { + if(flag) { // @ts-ignore this.connectStatus?.style.backgroundColor = 'green'; - this.businessMessage(decode); + // @ts-ignore + this.connectStatus?.title = 'The extended service is connected.'; + }else{ + // @ts-ignore + this.connectStatus?.style.backgroundColor = 'red'; + // @ts-ignore + this.connectStatus?.title = 'The extended service is not connected.'; } } @@ -129,8 +127,6 @@ export class WebSocketManager { this.status = GetStatuses.LOGINED; this.sessionId = decode.session_id; this.session = decode.session; - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'green'; //检查版本 this.getVersion(); } else if (decode.cmd === Constants.SESSION_EXCEED) { // session满了 @@ -152,6 +148,7 @@ export class WebSocketManager { return; } this.status = GetStatuses.READY; + this.extendTips(true); this.finalStatus(); } else if (decode.cmd === Constants.UPDATE_SUCCESS_CMD) { // 升级成功 this.status = GetStatuses.UPGRADESUCCESS; @@ -204,7 +201,7 @@ export class WebSocketManager { updateVersion(): void { // 扩展程序升级 let url = `https://${window.location.host.split(':')[0]}:${window.location.port - }/application/extend/hi-smart-perf-host-extend-update.zip`; + }${window.location.pathname}extend/hi-smart-perf-host-extend-update.zip`; fetch(url).then(response => { if (!response.ok) { throw new Error('No corresponding upgrade compression package found'); @@ -237,7 +234,7 @@ export class WebSocketManager { * listener是不同模块传来接收数据的函数 * 模块调用 */ -registerMessageListener(type: number, callback: Function, eventCallBack: Function, allowMultipleCallback: boolean = false): void { + registerMessageListener(type: number, callback: Function, eventCallBack: Function, allowMultipleCallback: boolean = false): void { let callbackObj = this.distributeMap.get(type); if (!callbackObj) { callbackObj = { @@ -282,7 +279,6 @@ registerMessageListener(type: number, callback: Function, eventCallBack: Functio } else { this.send(type, cmd, data); } - WebSocketManager.disaStatus = this.status; } send(type: number, cmd?: number, data?: Uint8Array): void { @@ -302,9 +298,6 @@ registerMessageListener(type: number, callback: Function, eventCallBack: Functio sendHeartbeat(): void { this.heartbeatInterval = window.setInterval(() => { if (this.status === GetStatuses.READY) { - WebSocketManager.disaStatus = GetStatuses.READY; - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'green'; this.send(TypeConstants.HEARTBEAT_TYPE, undefined, undefined); } }, Constants.INTERVAL_TIME); @@ -360,16 +353,10 @@ registerMessageListener(type: number, callback: Function, eventCallBack: Functio finalStatus(): void { if (this.reconnect !== -1) { if (this.status === GetStatuses.READY) { - WebSocketManager.disaStatus = GetStatuses.READY; - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'green'; // @ts-ignore this.sendMessage(this.reconnect, this.cacheInfo.get(this.reconnect)!.cmd, this.cacheInfo.get(this.reconnect)!.data); return; } - WebSocketManager.disaStatus = GetStatuses.UNCONNECTED; - // @ts-ignore - this.connectStatus?.style.backgroundColor = 'red'; this.distributeMap.get(this.reconnect)!.eventCallBack(this.status); } this.reconnect = -1; -- Gitee From e22cbfc0119e9853526e41cce405b92b937554de Mon Sep 17 00:00:00 2001 From: JustinYT Date: Mon, 16 Jun 2025 16:11:22 +0800 Subject: [PATCH 36/51] remove trace tag for outPoint.name_. Signed-off-by: JustinYT --- trace_streamer/src/parser/print_event_parser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/trace_streamer/src/parser/print_event_parser.cpp b/trace_streamer/src/parser/print_event_parser.cpp index c105f9d1..e24ca87e 100644 --- a/trace_streamer/src/parser/print_event_parser.cpp +++ b/trace_streamer/src/parser/print_event_parser.cpp @@ -270,6 +270,9 @@ void PrintEventParser::ParseSplitTraceMetaData(const std::string &dataStr, Trace TS_LOGD("traceMetaDatas size: %zu, dataStr: %s", traceMetaDatas.size(), dataStr.c_str()); return; } + if (!isAsynEvent) { + outPoint.name_ = std::move(traceMetaDatas[0]); + } std::string &marker = traceMetaDatas[1]; if (!marker.empty()) { -- Gitee From 8bb279c85deec32857d599e10e2a07f2a305af7f Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 16 Jun 2025 19:51:29 +0800 Subject: [PATCH 37/51] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/server/server-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/server/server-config.json b/ide/server/server-config.json index 0d231c8a..637b4034 100644 --- a/ide/server/server-config.json +++ b/ide/server/server-config.json @@ -1,4 +1,4 @@ { - "ServeInfo": "smartperf.rnd.huawei.com/statistics", + "ServeInfo": "127.0.0.1:9100/statistics", "MsgPublishFile": "" } \ No newline at end of file -- Gitee From c53829a184a48f08964565c01a6fed19b821433e Mon Sep 17 00:00:00 2001 From: danghongquan Date: Tue, 24 Jun 2025 14:56:01 +0800 Subject: [PATCH 38/51] fix:update MIN_CLOCK_SET_RATE_ARGS_COUNT Signed-off-by: danghongquan --- .../ptreader_parser/bytrace_parser/bytrace_event_parser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trace_streamer/src/parser/ptreader_parser/bytrace_parser/bytrace_event_parser.h b/trace_streamer/src/parser/ptreader_parser/bytrace_parser/bytrace_event_parser.h index d434e488..95ac451d 100644 --- a/trace_streamer/src/parser/ptreader_parser/bytrace_parser/bytrace_event_parser.h +++ b/trace_streamer/src/parser/ptreader_parser/bytrace_parser/bytrace_event_parser.h @@ -97,7 +97,7 @@ private: static const uint32_t MIN_CPU_IDLE_ARGS_COUNT = 2; static const uint32_t MIN_CPU_FREQUENCY_ARGS_COUNT = 2; static const uint32_t MIN_PROCESS_EXIT_ARGS_COUNT = 2; - static const uint32_t MIN_CLOCK_SET_RATE_ARGS_COUNT = 2; + static const uint32_t MIN_CLOCK_SET_RATE_ARGS_COUNT = 3; static const uint32_t MIN_CLOCK_ENABLE_ARGS_COUNT = 3; static const uint32_t MIN_CLOCK_DISABLE_ARGS_COUNT = 3; static const uint32_t MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT = 2; -- Gitee From 7719794198eb3fa8c80a28393fd1fc3cd8339628 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Wed, 18 Jun 2025 14:07:50 +0800 Subject: [PATCH 39/51] adjsut build for json,googletest,protobuf,sqlite,profiler. Signed-off-by: JustinYT --- trace_streamer/BUILD.gn | 2 +- trace_streamer/pare_third_party.sh | 54 +-- trace_streamer/sdk/demo_sdk/BUILD.gn | 8 +- .../protos/types/plugins/mock_data/BUILD.gn | 10 +- trace_streamer/sdk/demo_sdk/test/BUILD.gn | 13 +- .../demo_sdk/test/unittest/sdk_api_test.cpp | 21 +- trace_streamer/src/BUILD.gn | 3 +- trace_streamer/src/filter/BUILD.gn | 3 +- trace_streamer/src/parser/BUILD.gn | 1 + .../src/parser/ebpf_parser/BUILD.gn | 6 +- .../src/parser/hiperf_parser/BUILD.gn | 16 +- .../src/parser/pbreader_parser/BUILD.gn | 6 +- .../src/parser/rawtrace_parser/BUILD.gn | 4 +- .../src/proto_reader/protoc_plugin/BUILD.gn | 6 +- trace_streamer/src/protos/BUILD.gn | 340 ++++++++++++++++++ trace_streamer/src/protos/services/BUILD.gn | 10 +- .../src/protos/smartperf_host/BUILD.gn | 10 +- .../protos/types/plugins/agent_data/BUILD.gn | 6 +- .../types/plugins/bytrace_plugin/BUILD.gn | 8 +- .../protos/types/plugins/cpu_data/BUILD.gn | 6 +- .../protos/types/plugins/diskio_data/BUILD.gn | 6 +- .../types/plugins/ffrt_profiler/BUILD.gn | 10 +- .../plugins/ftrace_data/default/BUILD.gn | 6 +- .../protos/types/plugins/hidump_data/BUILD.gn | 6 +- .../protos/types/plugins/hiebpf_data/BUILD.gn | 8 +- .../protos/types/plugins/hilog_data/BUILD.gn | 6 +- .../types/plugins/hiperf_call_plugin/BUILD.gn | 4 +- .../protos/types/plugins/hiperf_data/BUILD.gn | 8 +- .../types/plugins/hisysevent_data/BUILD.gn | 6 +- .../protos/types/plugins/js_memory/BUILD.gn | 6 +- .../protos/types/plugins/memory_data/BUILD.gn | 6 +- .../protos/types/plugins/native_hook/BUILD.gn | 10 +- .../types/plugins/network_data/BUILD.gn | 6 +- .../types/plugins/process_data/BUILD.gn | 6 +- .../protos/types/plugins/sample_data/BUILD.gn | 4 +- .../protos/types/plugins/stream_data/BUILD.gn | 6 +- .../protos/types/plugins/test_data/BUILD.gn | 6 +- .../protos/types/plugins/xpower_data/BUILD.gn | 6 +- trace_streamer/src/table/BUILD.gn | 2 +- trace_streamer/src/table/base/BUILD.gn | 2 +- trace_streamer/src/trace_data/BUILD.gn | 2 +- trace_streamer/src/version.cpp | 4 +- trace_streamer/test/BUILD.gn | 9 +- .../test/test_fuzzer/bytrace_fuzzer/BUILD.gn | 5 +- .../test/test_fuzzer/htrace_fuzzer/BUILD.gn | 5 +- .../test/test_fuzzer/selector_fuzzer/BUILD.gn | 5 +- trace_streamer/test/unittest/BUILD.gn | 159 ++++++++ .../test/unittest/base/export_test.cpp | 1 + .../test/unittest/ebpf/bio_parser_test.cpp | 1 + .../unittest/ebpf/ebpf_file_system_test.cpp | 1 + .../test/unittest/ebpf/ebpf_parser_test.cpp | 1 + .../ebpf/paged_memory_parser_test.cpp | 1 + .../unittest/filter/animation_filter_test.cpp | 1 + .../unittest/filter/app_start_filter_test.cpp | 1 + .../unittest/filter/binder_filter_test.cpp | 1 + .../unittest/filter/clock_filter_test.cpp | 1 + .../test/unittest/filter/cpu_filter_test.cpp | 236 ++++++------ .../unittest/filter/filter_filter_test.cpp | 1 + .../unittest/filter/frame_filter_test.cpp | 54 +-- .../test/unittest/filter/irq_filter_test.cpp | 1 + .../unittest/filter/measure_filter_test.cpp | 1 + .../unittest/filter/process_filter_test.cpp | 1 + .../unittest/filter/slice_filter_test.cpp | 1 + .../unittest/filter/task_pool_filter_test.cpp | 3 + .../unittest/interface/rpc_server_test.cpp | 4 +- .../interface/split_file_data_test.cpp | 1 + .../unittest/interface/wasm_func_test.cpp | 1 + .../pbreader/parser_pbreader_test.cpp | 1 + .../unittest/pbreader/proto_reader_test.cpp | 1 + .../arkts/js_cpu_profiler_test.cpp | 1 + .../pbreader_parser/arkts/js_memory_test.cpp | 1 + .../pbreader_parser/diskio_parser_test.cpp | 1 + .../pbreader_parser/hidump_parser_test.cpp | 1 + .../pbreader_parser/hilog_parser_test.cpp | 1 + .../hisys_event_parser_test.cpp | 1 + .../htrace_binder_event_test.cpp | 1 + .../htrace_cpu_detail_parser_test.cpp | 1 + .../htrace_event_parser_test.cpp | 3 + .../pbreader_parser/htrace_irq_event_test.cpp | 1 + .../native_memory/native_hook_parser_test.cpp | 1 + .../pbreader_cpu_data_parser_test.cpp | 1 + .../pbreader_ffrt_parser_test.cpp | 1 + .../pbreader_mem_parser_test.cpp | 1 + .../pbreader_network_parser_test.cpp | 1 + .../pbreader_process_parser_test.cpp | 1 + .../pbreader_sys_mem_parser_test.cpp | 1 + .../pbreader_sys_vmem_parser_test.cpp | 1 + .../pbreader_xpower_parser_test.cpp | 1 + .../pbreader_parser/smaps_parser_test.cpp | 1 + .../ptreader_parser/event_parser_test.cpp | 102 ++++++ .../ptreader_parser/ptreader_parser_test.cpp | 1 + .../test/unittest/query/query_file_test.cpp | 1 + .../unittest/query/query_metrics_test.cpp | 1 + .../test/unittest/query/span_join_test.cpp | 1 + .../query/sqllite_prepar_cache_data_test.cpp | 1 + .../rawtrace/ftrace_field_processor_test.cpp | 1 + .../rawtrace_cpu_detail_parse_test.cpp | 6 + .../rawtrace/rawtrace_parser_test.cpp | 1 + .../test/unittest/table/table_test.cpp | 17 +- 99 files changed, 986 insertions(+), 325 deletions(-) create mode 100644 trace_streamer/src/protos/BUILD.gn create mode 100644 trace_streamer/test/unittest/BUILD.gn diff --git a/trace_streamer/BUILD.gn b/trace_streamer/BUILD.gn index 22c6002d..a6601897 100644 --- a/trace_streamer/BUILD.gn +++ b/trace_streamer/BUILD.gn @@ -19,7 +19,7 @@ group("trace_streamer") { deps = [ "test:fuzztest" ] testonly = true } else if (is_protoc) { - deps = [ "${THIRD_PARTY}/protobuf:protoc" ] + deps = [ "src/protos:protoc" ] } else if (is_spb) { deps = [ "src/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", diff --git a/trace_streamer/pare_third_party.sh b/trace_streamer/pare_third_party.sh index 97d8c1d6..1a695a4f 100755 --- a/trace_streamer/pare_third_party.sh +++ b/trace_streamer/pare_third_party.sh @@ -29,26 +29,17 @@ fi cd third_party if [ ! -f "sqlite/BUILD.gn" ];then - rm -rf sqlite - git clone git@gitee.com:openharmony/third_party_sqlite.git - if [ -d "third_party_sqlite" ];then - mv third_party_sqlite sqlite - cd sqlite - git reset --hard d21e412dbc6f2cdde2e4c9828e2450fcfca4fbe9 - cd .. - $cp ../prebuilts/patch_sqlite/sqlite3build.gn ../third_party/sqlite/BUILD.gn - fi + git clone git@gitee.com:openharmony/third_party_sqlite.git sqlite + cd sqlite + git reset --hard d21e412dbc6f2cdde2e4c9828e2450fcfca4fbe9 + cd .. fi + if [ ! -f "protobuf/BUILD.gn" ];then - rm -rf protobuf - git clone git@gitee.com:openharmony/third_party_protobuf.git - if [ -d "third_party_protobuf" ];then - mv third_party_protobuf protobuf - cd protobuf - git reset --hard aceafed4cf26d7a6be8169ae887cc13b749d5515 - cd .. - $cp ../prebuilts/patch_protobuf/protobufbuild.gn ../third_party/protobuf/BUILD.gn - fi + git clone git@gitee.com:openharmony/third_party_protobuf.git protobuf + cd protobuf + git reset --hard aceafed4cf26d7a6be8169ae887cc13b749d5515 + cd .. fi if [ ! -f "zlib/BUILD.gn" ];then @@ -60,21 +51,11 @@ if [ ! -f "bzip2/BUILD.gn" ];then fi if [ ! -f "googletest/BUILD.gn" ];then - rm -rf googletest - git clone --depth=1 git@gitee.com:openharmony/third_party_googletest.git - if [ -d "third_party_googletest" ];then - mv third_party_googletest googletest - $cp ../prebuilts/patch_googletest/googletestbuild.gn ../third_party/googletest/BUILD.gn - $patch -p1 < ../prebuilts/patch_googletest/gtest.patch - fi + git clone --depth=1 git@gitee.com:openharmony/third_party_googletest.git googletest fi -if [ ! -f "json/BUILD.gn" ];then - rm -rf json - git clone --depth=1 git@gitee.com:openharmony/third_party_json.git - if [ -d "third_party_json" ];then - mv third_party_json json - fi +if [ ! -d "json" ];then + git clone --depth=1 git@gitee.com:openharmony/third_party_json.git json fi if [ ! -d "libbpf" ];then @@ -101,15 +82,8 @@ if [ ! -d "commonlibrary/c_utils" ];then git clone --depth=1 git@gitee.com:openharmony/commonlibrary_c_utils.git commonlibrary/c_utils fi -if [ ! -f "profiler/device/plugins/ftrace_plugin/include/ftrace_common_type.h" ];then - rm -rf profiler - git clone --depth=1 git@gitee.com:openharmony/developtools_profiler.git - if [ -d "developtools_profiler" ];then - mkdir -p profiler/device/plugins/ftrace_plugin/include - $cp developtools_profiler/device/plugins/ftrace_plugin/include/ftrace_common_type.h profiler/device/plugins/ftrace_plugin/include - $cp developtools_profiler/device/plugins/ftrace_plugin/include/ftrace_namespace.h profiler/device/plugins/ftrace_plugin/include - rm -rf developtools_profiler - fi +if [ ! -d "profiler" ];then + git clone --depth=1 git@gitee.com:openharmony/developtools_profiler.git profiler fi if [ ! -d "llvm-project" ];then diff --git a/trace_streamer/sdk/demo_sdk/BUILD.gn b/trace_streamer/sdk/demo_sdk/BUILD.gn index 9c4e5bd0..39419e85 100644 --- a/trace_streamer/sdk/demo_sdk/BUILD.gn +++ b/trace_streamer/sdk/demo_sdk/BUILD.gn @@ -34,8 +34,8 @@ ohos_source_set("lib") { ] deps = [ ":trace_streamer_sdk", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "${SRC}/base", @@ -108,9 +108,9 @@ ohos_source_set("trace_streamer_sdk") { "${THIRD_PARTY}/bounds_checking_function/include", ] deps = [ + "${OHOS_TRACE_STREAMER_PROTOS_DIR}:ts_sqlite", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/parser/hiperf_parser:libsec_static", "${SRC}/base:base", - "${THIRD_PARTY}/bounds_checking_function:libsec_static", - "${THIRD_PARTY}/sqlite:sqlite", "plugin:sdk_plugin", ] public_deps = [ "protos/types/plugins/mock_data:mock_data_cpp" ] diff --git a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/BUILD.gn b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/BUILD.gn index 855f3b17..7a434852 100644 --- a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/BUILD.gn +++ b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/BUILD.gn @@ -60,7 +60,7 @@ action("mock_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin", ] } @@ -69,8 +69,8 @@ action("mock_data_cpp_gen") { ohos_source_set("mock_data_cpp") { deps = [ ":mock_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":cpu_include_config" ] @@ -80,8 +80,8 @@ ohos_source_set("mock_data_cpp") { ohos_source_set("mock_data_cpp_standard") { deps = [ ":mock_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":cpu_include_config" ] diff --git a/trace_streamer/sdk/demo_sdk/test/BUILD.gn b/trace_streamer/sdk/demo_sdk/test/BUILD.gn index d92e5841..ed98fb1c 100644 --- a/trace_streamer/sdk/demo_sdk/test/BUILD.gn +++ b/trace_streamer/sdk/demo_sdk/test/BUILD.gn @@ -19,11 +19,11 @@ if (target == "sdkdemotest") { ohos_unittest("trace_streamer_sdk_ut") { sources = [ "unittest/sdk_api_test.cpp" ] deps = [ - "${THIRD_PARTY}/googletest:gtest", - "${THIRD_PARTY}/googletest:gtest_main", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", - "${THIRD_PARTY}/sqlite:sqlite", + "//test/unittest:gtest", + "//test/unittest:gtest_main", + "${SRC}/protos:protobuf_lite_static", + "${SRC}/protos:protobuf_static", + "${SRC}:ts_sqlite", "../:trace_streamer_sdk", ] include_dirs = [ @@ -46,10 +46,11 @@ if (target == "sdkdemotest") { "${THIRD_PARTY}/googletest/googletest/include/gtest", "${THIRD_PARTY}/protobuf/src", "${THIRD_PARTY}/json/single_include/nlohmann", + "${THIRD_PARTY}/zlib" ] cflags = [ "-Wno-inconsistent-missing-override", - "-Dprivate=public", #allow test code access private members + # "-Dprivate=public", #allow test code access private members "-fprofile-arcs", "-ftest-coverage", "-Wno-unused-command-line-argument", diff --git a/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp b/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp index b87aa683..cf85ef5e 100644 --- a/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp +++ b/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp @@ -15,6 +15,7 @@ #include #include +#define private public #include "gpu_counter_object_table.h" #include "gpu_counter_table.h" #include "mock_plugin_result.pb.h" @@ -245,7 +246,7 @@ HWTEST_F(SDKApiTest, CurrentDataForCounterObjectWithManuallyTableName, TestSize. { TS_LOGI("test1-7"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + auto ret = SDKSetTableName(" ", "second_table", " ", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -288,7 +289,7 @@ HWTEST_F(SDKApiTest, WrongDataForCounterObjectWithManuallyTableName, TestSize.Le { TS_LOGI("test1-9"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + auto ret = SDKSetTableName(" ", "second_table", " ", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -310,7 +311,7 @@ HWTEST_F(SDKApiTest, WrongDataForCounterObject, TestSize.Level1) { TS_LOGI("test1-10"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + auto ret = SDKSetTableName(" ", "second_table", " ", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -353,7 +354,7 @@ HWTEST_F(SDKApiTest, CurrentDataForCounterWithManuallyTableName, TestSize.Level1 { TS_LOGI("test1-12"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName("first_table", " ", " ", " "); + auto ret = SDKSetTableName("first_table", " ", " ", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -396,7 +397,7 @@ HWTEST_F(SDKApiTest, WrongDataForCounterWithManuallyTableName, TestSize.Level1) { TS_LOGI("test1-14"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName("first_table", " ", " ", " "); + auto ret = SDKSetTableName("first_table", " ", " ", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -460,7 +461,7 @@ HWTEST_F(SDKApiTest, CurrentDataForSliceObjectWithManuallyTableName, TestSize.Le { TS_LOGI("test1-17"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + auto ret = SDKSetTableName(" ", " ", " ", "fourth_table"); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -503,7 +504,7 @@ HWTEST_F(SDKApiTest, WrongDataForSliceObjectWithManuallyTableName, TestSize.Leve { TS_LOGI("test1-19"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + auto ret = SDKSetTableName(" ", " ", " ", "fourth_table"); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -525,7 +526,7 @@ HWTEST_F(SDKApiTest, WrongDataForSliceObject, TestSize.Level1) { TS_LOGI("test1-20"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + auto ret = SDKSetTableName(" ", " ", " ", "fourth_table"); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -568,7 +569,7 @@ HWTEST_F(SDKApiTest, CurrentDataForSliceWithManuallyTableName, TestSize.Level1) { TS_LOGI("test1-22"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + auto ret = SDKSetTableName(" ", " ", "third_table", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); @@ -611,7 +612,7 @@ HWTEST_F(SDKApiTest, WrongDataForSliceWithManuallyTableName, TestSize.Level1) { TS_LOGI("test1-24"); SetRpcServer(rpcServer); - auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + auto ret = SDKSetTableName(" ", " ", "third_table", " "); ret = rpcServer->demoTs_->sdkDataParser_->GetJsonConfig(QueryResultCallback); EXPECT_EQ(0, ret); ret = rpcServer->demoTs_->sdkDataParser_->CreateTableByJson(); diff --git a/trace_streamer/src/BUILD.gn b/trace_streamer/src/BUILD.gn index c40825e3..26cce508 100644 --- a/trace_streamer/src/BUILD.gn +++ b/trace_streamer/src/BUILD.gn @@ -17,6 +17,7 @@ if (use_wasm) { import("//gn/wasm.gni") } +# for third part sqlite ohos_source_set("ts_sqlite") { subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" part_name = "${OHOS_PROFILER_PART_NAME}" @@ -115,7 +116,7 @@ ohos_source_set("trace_streamer_source") { public_deps = [] if (!use_wasm && !is_test && !is_fuzz) { public_deps += [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } diff --git a/trace_streamer/src/filter/BUILD.gn b/trace_streamer/src/filter/BUILD.gn index cb8a9f50..5d4a5fd3 100644 --- a/trace_streamer/src/filter/BUILD.gn +++ b/trace_streamer/src/filter/BUILD.gn @@ -42,13 +42,14 @@ config("filter_cfg") { "${SRC}/filter/hi_sysevent_filter", "${SRC}/cfg", "${SRC}", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/sqlite/include", "${PERF_DIR}/hiperf/include", "${PERF_DIR}/hiperf/include/nonlinux/linux", "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/innerkits/unwinder/include", "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/nonlinux", "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/common", + "${THIRD_PARTY}/hiviewdfx/faultloggerd/common/dfxlog", "${THIRD_PARTY}/hiviewdfx/faultloggerd/common/dfxutil", "${THIRD_PARTY}/hiviewdfx/faultloggerd/common/dfxlog", "${PERF_DIR}/hiperf/include/nonlinux", diff --git a/trace_streamer/src/parser/BUILD.gn b/trace_streamer/src/parser/BUILD.gn index 7cfc3b1e..aea42aa3 100644 --- a/trace_streamer/src/parser/BUILD.gn +++ b/trace_streamer/src/parser/BUILD.gn @@ -17,6 +17,7 @@ import("../../build/ts.gni") config("parser_base_cfg") { include_dirs = [ "${THIRD_PARTY}/protobuf/src", + "${THIRD_PARTY}/protobuf/third_party/abseil-cpp", "${THIRD_PARTY}/sqlite/include", "${SRC}/base", "${SRC}/cfg", diff --git a/trace_streamer/src/parser/ebpf_parser/BUILD.gn b/trace_streamer/src/parser/ebpf_parser/BUILD.gn index 9446f852..c4e1925d 100644 --- a/trace_streamer/src/parser/ebpf_parser/BUILD.gn +++ b/trace_streamer/src/parser/ebpf_parser/BUILD.gn @@ -28,7 +28,7 @@ config("ebpf_parser_cfg") { "../../cfg", "../../trace_streamer", "../../proto_reader/include", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/sqlite/include", "${THIRD_PARTY}/bounds_checking_function/include", ] @@ -80,7 +80,7 @@ ohos_static_library("ebpf_parser") { "../hiperf_parser:ts_hiperf_src", ] deps = [ - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] } diff --git a/trace_streamer/src/parser/hiperf_parser/BUILD.gn b/trace_streamer/src/parser/hiperf_parser/BUILD.gn index 0dd179d1..70008c66 100644 --- a/trace_streamer/src/parser/hiperf_parser/BUILD.gn +++ b/trace_streamer/src/parser/hiperf_parser/BUILD.gn @@ -14,7 +14,7 @@ import("//build/ohos.gni") import("../../../build/ts.gni") -# THIRD_PARTY for bzip2 +# for third part bzip2 config("bzip2_config") { include_dirs = [ "${THIRD_PARTY}/bzip2" ] } @@ -43,7 +43,7 @@ ohos_source_set("libbz2") { subsystem_name = "thirdparty" } -# THIRD_PARTY for zlib +# for third part zlib config("zlib_config") { cflags = [ "-Wno-incompatible-pointer-types", @@ -87,7 +87,7 @@ ohos_source_set("libz") { subsystem_name = "thirdparty" } -# THIRD_PARTY for bounds_checking_function +# for third part bounds_checking_function sources_libsec_with_ts_common = [ "${THIRD_PARTY}/bounds_checking_function/src/fscanf_s.c", "${THIRD_PARTY}/bounds_checking_function/src/fwscanf_s.c", @@ -144,7 +144,7 @@ ohos_source_set("libsec_static") { ] } -# THIRD_PARTY for hiviewdfx faultloggerd +# for third part hiviewdfx faultloggerd config("faultloggerd_config") { cflags = [ "-D ALWAYSTRUE", @@ -188,7 +188,7 @@ ohos_source_set("libfaultloggerd") { subsystem_name = "thirdparty" } -# THIRD_PARTY for hiperf +# for third part hiperf sources_platform_with_ts_common = [ "${PERF_DIR}/hiperf/src/dwarf_encoding.cpp", "${PERF_DIR}/hiperf/src/option.cpp", @@ -281,7 +281,7 @@ config("hiperf_parser_cfg") { "../../proto_reader/include", "${THIRD_PARTY}/bounds_checking_function/include", "${THIRD_PARTY}/sqlite/include", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${COMMON_LIBRARY}/c_utils/base/include", "${THIRD_PARTY}/googletest/googletest/include", ] @@ -326,8 +326,8 @@ if (enable_hiperf) { ] public_deps = [ ":ts_hiperf_src", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] if (enable_addr2line) { public_deps += [ diff --git a/trace_streamer/src/parser/pbreader_parser/BUILD.gn b/trace_streamer/src/parser/pbreader_parser/BUILD.gn index 789ffc41..d8009c67 100644 --- a/trace_streamer/src/parser/pbreader_parser/BUILD.gn +++ b/trace_streamer/src/parser/pbreader_parser/BUILD.gn @@ -32,7 +32,7 @@ ohos_source_set("pbreader_parser_src") { "../../trace_streamer", "../../metrics", "${THIRD_PARTY}/bounds_checking_function/include", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/sqlite/include", "${THIRD_PARTY}/json/single_include/nlohmann", "../../filter", @@ -127,9 +127,9 @@ ohos_source_set("pbreader_parser_src") { [ "${EXTEND_SRC}/parser/pbreader_stream_parser:stream_extend_parser" ] } public_deps += [ + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/services:ts_all_type_cpp_standard", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", "../hiperf_parser:libz", ] } diff --git a/trace_streamer/src/parser/rawtrace_parser/BUILD.gn b/trace_streamer/src/parser/rawtrace_parser/BUILD.gn index 646ed3af..0187985a 100755 --- a/trace_streamer/src/parser/rawtrace_parser/BUILD.gn +++ b/trace_streamer/src/parser/rawtrace_parser/BUILD.gn @@ -78,9 +78,9 @@ ohos_static_library("rawtrace_parser") { } public_deps = [ + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/services:ts_all_type_cpp_standard", "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/types/plugins/ftrace_data/${device_kernel_version}:ts_ftrace_data_cpp", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", ] } diff --git a/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn b/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn index e61ade48..646018c6 100644 --- a/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn +++ b/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn @@ -17,13 +17,13 @@ ohos_executable("protoreader_plugin") { part_name = "${OHOS_PROFILER_PART_NAME}" sources = [ "proto_reader_plugin.cpp" ] deps = [ + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc_lib(${host_toolchain})", "${SRC}/base:string_help", - "${THIRD_PARTY}/protobuf:protobuf_static(${host_toolchain})", - "${THIRD_PARTY}/protobuf:protoc_lib(${host_toolchain})", ] include_dirs = [ "${SRC}/base", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "//third_party/bounds_checking_function/include", ] } diff --git a/trace_streamer/src/protos/BUILD.gn b/trace_streamer/src/protos/BUILD.gn new file mode 100644 index 00000000..c029647d --- /dev/null +++ b/trace_streamer/src/protos/BUILD.gn @@ -0,0 +1,340 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") +import("../../build/ts.gni") + +# for third part protobuf +config("protobuf_config") { + include_dirs = [ "${THIRD_PARTY}/protobuf/src" ] +} +protobuf_dir = "${THIRD_PARTY}/protobuf/src/google/protobuf" +protobuf_lite_src = [ + "$protobuf_dir/any_lite.cc", + "$protobuf_dir/arena.cc", + "$protobuf_dir/extension_set.cc", + "$protobuf_dir/generated_enum_util.cc", + "$protobuf_dir/generated_message_table_driven_lite.cc", + "$protobuf_dir/generated_message_util.cc", + "$protobuf_dir/implicit_weak_message.cc", + "$protobuf_dir/io/coded_stream.cc", + "$protobuf_dir/io/io_win32.cc", + "$protobuf_dir/io/strtod.cc", + "$protobuf_dir/io/zero_copy_stream.cc", + "$protobuf_dir/io/zero_copy_stream_impl.cc", + "$protobuf_dir/io/zero_copy_stream_impl_lite.cc", + "$protobuf_dir/message_lite.cc", + "$protobuf_dir/parse_context.cc", + "$protobuf_dir/repeated_field.cc", + "$protobuf_dir/stubs/bytestream.cc", + "$protobuf_dir/stubs/common.cc", + "$protobuf_dir/stubs/int128.cc", + "$protobuf_dir/stubs/status.cc", + "$protobuf_dir/stubs/statusor.cc", + "$protobuf_dir/stubs/stringpiece.cc", + "$protobuf_dir/stubs/stringprintf.cc", + "$protobuf_dir/stubs/structurally_valid.cc", + "$protobuf_dir/stubs/strutil.cc", + "$protobuf_dir/stubs/time.cc", + "$protobuf_dir/wire_format_lite.cc", +] + +protobuf_src = [ + "$protobuf_dir/any.cc", + "$protobuf_dir/any.pb.cc", + "$protobuf_dir/api.pb.cc", + "$protobuf_dir/compiler/importer.cc", + "$protobuf_dir/compiler/parser.cc", + "$protobuf_dir/descriptor.cc", + "$protobuf_dir/descriptor.pb.cc", + "$protobuf_dir/descriptor_database.cc", + "$protobuf_dir/duration.pb.cc", + "$protobuf_dir/dynamic_message.cc", + "$protobuf_dir/empty.pb.cc", + "$protobuf_dir/extension_set_heavy.cc", + "$protobuf_dir/field_mask.pb.cc", + "$protobuf_dir/generated_message_reflection.cc", + "$protobuf_dir/generated_message_table_driven.cc", + "$protobuf_dir/io/gzip_stream.cc", + "$protobuf_dir/io/printer.cc", + "$protobuf_dir/io/tokenizer.cc", + "$protobuf_dir/map_field.cc", + "$protobuf_dir/message.cc", + "$protobuf_dir/reflection_ops.cc", + "$protobuf_dir/service.cc", + "$protobuf_dir/source_context.pb.cc", + "$protobuf_dir/struct.pb.cc", + "$protobuf_dir/stubs/substitute.cc", + "$protobuf_dir/text_format.cc", + "$protobuf_dir/timestamp.pb.cc", + "$protobuf_dir/type.pb.cc", + "$protobuf_dir/unknown_field_set.cc", + "$protobuf_dir/util/delimited_message_util.cc", + "$protobuf_dir/util/field_comparator.cc", + "$protobuf_dir/util/field_mask_util.cc", + "$protobuf_dir/util/internal/datapiece.cc", + "$protobuf_dir/util/internal/default_value_objectwriter.cc", + "$protobuf_dir/util/internal/error_listener.cc", + "$protobuf_dir/util/internal/field_mask_utility.cc", + "$protobuf_dir/util/internal/json_escaping.cc", + "$protobuf_dir/util/internal/json_objectwriter.cc", + "$protobuf_dir/util/internal/json_stream_parser.cc", + "$protobuf_dir/util/internal/object_writer.cc", + "$protobuf_dir/util/internal/proto_writer.cc", + "$protobuf_dir/util/internal/protostream_objectsource.cc", + "$protobuf_dir/util/internal/protostream_objectwriter.cc", + "$protobuf_dir/util/internal/type_info.cc", + "$protobuf_dir/util/internal/type_info_test_helper.cc", + "$protobuf_dir/util/internal/utility.cc", + "$protobuf_dir/util/json_util.cc", + "$protobuf_dir/util/message_differencer.cc", + "$protobuf_dir/util/time_util.cc", + "$protobuf_dir/util/type_resolver_util.cc", + "$protobuf_dir/wire_format.cc", + "$protobuf_dir/wrappers.pb.cc", +] +if (use_wasm) { + source_set("protobuf_lite_static") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + if (wasm_use_thread) { + cflags += [ + "-mbulk-memory", + "-matomics", + ] + } + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf_lite_static") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + public_configs = [ ":protobuf_config" ] + } +} +if (use_wasm) { + source_set("protobuf_static") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + if (wasm_use_thread) { + cflags += [ + "-mbulk-memory", + "-matomics", + ] + } + + deps = [ ":protobuf_lite_static" ] + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf_static") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-ftrapv", + "-fstack-protector-strong", + "-fstack-protector-all", + "-D_FORTIFY_SOURCE=2 -O2", + "-std=c++17", + ] + + ldflags = [ "-fstack-protector" ] + if (!is_mac) { + ldflags += [ + "-fuse-ld=gold", + "-Wl,--gc-sections", + "-Wl,-O1", + "-fpie", + "-pie", + ] + } + + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + + deps = [ ":protobuf_lite_static" ] + + public_configs = [ ":protobuf_config" ] + } + source_set("protoc_lib") { + sources = [ + "$protobuf_dir/compiler/code_generator.cc", + "$protobuf_dir/compiler/command_line_interface.cc", + "$protobuf_dir/compiler/cpp/cpp_enum.cc", + "$protobuf_dir/compiler/cpp/cpp_enum_field.cc", + "$protobuf_dir/compiler/cpp/cpp_extension.cc", + "$protobuf_dir/compiler/cpp/cpp_field.cc", + "$protobuf_dir/compiler/cpp/cpp_file.cc", + "$protobuf_dir/compiler/cpp/cpp_generator.cc", + "$protobuf_dir/compiler/cpp/cpp_helpers.cc", + "$protobuf_dir/compiler/cpp/cpp_map_field.cc", + "$protobuf_dir/compiler/cpp/cpp_message.cc", + "$protobuf_dir/compiler/cpp/cpp_message_field.cc", + "$protobuf_dir/compiler/cpp/cpp_padding_optimizer.cc", + "$protobuf_dir/compiler/cpp/cpp_primitive_field.cc", + "$protobuf_dir/compiler/cpp/cpp_service.cc", + "$protobuf_dir/compiler/cpp/cpp_string_field.cc", + "$protobuf_dir/compiler/csharp/csharp_doc_comment.cc", + "$protobuf_dir/compiler/csharp/csharp_enum.cc", + "$protobuf_dir/compiler/csharp/csharp_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_field_base.cc", + "$protobuf_dir/compiler/csharp/csharp_generator.cc", + "$protobuf_dir/compiler/csharp/csharp_helpers.cc", + "$protobuf_dir/compiler/csharp/csharp_map_field.cc", + "$protobuf_dir/compiler/csharp/csharp_message.cc", + "$protobuf_dir/compiler/csharp/csharp_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_reflection_class.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_source_generator_base.cc", + "$protobuf_dir/compiler/csharp/csharp_wrapper_field.cc", + "$protobuf_dir/compiler/java/java_context.cc", + "$protobuf_dir/compiler/java/java_doc_comment.cc", + "$protobuf_dir/compiler/java/java_enum.cc", + "$protobuf_dir/compiler/java/java_enum_field.cc", + "$protobuf_dir/compiler/java/java_enum_field_lite.cc", + "$protobuf_dir/compiler/java/java_enum_lite.cc", + "$protobuf_dir/compiler/java/java_extension.cc", + "$protobuf_dir/compiler/java/java_extension_lite.cc", + "$protobuf_dir/compiler/java/java_field.cc", + "$protobuf_dir/compiler/java/java_file.cc", + "$protobuf_dir/compiler/java/java_generator.cc", + "$protobuf_dir/compiler/java/java_generator_factory.cc", + "$protobuf_dir/compiler/java/java_helpers.cc", + "$protobuf_dir/compiler/java/java_map_field.cc", + "$protobuf_dir/compiler/java/java_map_field_lite.cc", + "$protobuf_dir/compiler/java/java_message.cc", + "$protobuf_dir/compiler/java/java_message_builder.cc", + "$protobuf_dir/compiler/java/java_message_builder_lite.cc", + "$protobuf_dir/compiler/java/java_message_field.cc", + "$protobuf_dir/compiler/java/java_message_field_lite.cc", + "$protobuf_dir/compiler/java/java_message_lite.cc", + "$protobuf_dir/compiler/java/java_name_resolver.cc", + "$protobuf_dir/compiler/java/java_primitive_field.cc", + "$protobuf_dir/compiler/java/java_primitive_field_lite.cc", + "$protobuf_dir/compiler/java/java_service.cc", + "$protobuf_dir/compiler/java/java_shared_code_generator.cc", + "$protobuf_dir/compiler/java/java_string_field.cc", + "$protobuf_dir/compiler/java/java_string_field_lite.cc", + "$protobuf_dir/compiler/js/js_generator.cc", + "$protobuf_dir/compiler/js/well_known_types_embed.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_extension.cc", + "$protobuf_dir/compiler/objectivec/objectivec_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_file.cc", + "$protobuf_dir/compiler/objectivec/objectivec_generator.cc", + "$protobuf_dir/compiler/objectivec/objectivec_helpers.cc", + "$protobuf_dir/compiler/objectivec/objectivec_map_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_oneof.cc", + "$protobuf_dir/compiler/objectivec/objectivec_primitive_field.cc", + "$protobuf_dir/compiler/php/php_generator.cc", + "$protobuf_dir/compiler/plugin.cc", + "$protobuf_dir/compiler/plugin.pb.cc", + "$protobuf_dir/compiler/python/python_generator.cc", + "$protobuf_dir/compiler/ruby/ruby_generator.cc", + "$protobuf_dir/compiler/subprocess.cc", + "$protobuf_dir/compiler/zip_writer.cc", + ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + if (!use_wasm) { + configs = default_configs + } + cflags_cc = [ + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-private-field", + ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-Wno-unused-function", + "-std=c++17", + ] + + deps = [ + ":protobuf_lite_static", + ":protobuf_static", + ] + + public_configs = [ ":protobuf_config" ] + } + executable("protoc") { + sources = [ "$protobuf_dir/compiler/main.cc" ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "${THIRD_PARTY}/protobuf/src", + ] + deps = [ ":protoc_lib" ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + ] + if (is_mingw) { + output_extension = "exe" + } + } +} diff --git a/trace_streamer/src/protos/services/BUILD.gn b/trace_streamer/src/protos/services/BUILD.gn index d313de69..70eb522a 100644 --- a/trace_streamer/src/protos/services/BUILD.gn +++ b/trace_streamer/src/protos/services/BUILD.gn @@ -60,7 +60,7 @@ action("ts_all_type_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -71,8 +71,8 @@ ohos_source_set("ts_all_type_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_all_type_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":public_configs" ] @@ -83,8 +83,8 @@ ohos_source_set("ts_all_type_cpp_standard") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_all_type_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":public_configs" ] diff --git a/trace_streamer/src/protos/smartperf_host/BUILD.gn b/trace_streamer/src/protos/smartperf_host/BUILD.gn index 1ca1e6cc..d6541d75 100644 --- a/trace_streamer/src/protos/smartperf_host/BUILD.gn +++ b/trace_streamer/src/protos/smartperf_host/BUILD.gn @@ -56,7 +56,7 @@ action("ts_all_sph_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -67,8 +67,8 @@ ohos_source_set("ts_all_sph_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_all_sph_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":public_configs" ] @@ -79,8 +79,8 @@ ohos_source_set("ts_all_sph_cpp_standard") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_all_sph_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":public_configs" ] diff --git a/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn index bf8b97e0..beae9570 100644 --- a/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn @@ -65,7 +65,7 @@ action("ts_agent_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -76,8 +76,8 @@ ohos_source_set("ts_agent_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_agent_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":agent_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn b/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn index c02768e4..45e08ec5 100644 --- a/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn @@ -63,8 +63,8 @@ ohos_source_set("ts_bytrace_plugin_protos_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_bytrace_plugin_protos_protoc" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":bytrace_plugin_protos_config" ] @@ -76,8 +76,8 @@ ohos_source_set("ts_bytrace_plugin_protos_cpp_standard") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_bytrace_plugin_protos_protoc" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":bytrace_plugin_protos_config" ] diff --git a/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn index 410fecf6..25dfbe10 100644 --- a/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_cpu_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_cpu_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_cpu_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":cpu_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn index c7d3690a..bdf660b3 100644 --- a/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_diskio_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_diskio_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_diskio_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":diskio_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/ffrt_profiler/BUILD.gn b/trace_streamer/src/protos/types/plugins/ffrt_profiler/BUILD.gn index 66a13d4f..4c821dfa 100644 --- a/trace_streamer/src/protos/types/plugins/ffrt_profiler/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/ffrt_profiler/BUILD.gn @@ -58,7 +58,7 @@ action("ts_ffrt_profiler_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_ffrt_profiler_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_ffrt_profiler_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":ffrt_profiler_include_config" ] @@ -81,8 +81,8 @@ ohos_source_set("ffrt_profiler_data_reader") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_ffrt_profiler_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":ffrt_profiler_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/default/BUILD.gn b/trace_streamer/src/protos/types/plugins/ftrace_data/default/BUILD.gn index cab63254..d8a2e5ef 100644 --- a/trace_streamer/src/protos/types/plugins/ftrace_data/default/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/default/BUILD.gn @@ -56,7 +56,7 @@ action("ts_all_proto_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -71,8 +71,8 @@ ohos_source_set("ts_ftrace_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_all_proto_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":public_configs" ] diff --git a/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn index 7db56c83..7e273d40 100644 --- a/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_hidump_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_hidump_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hidump_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hidump_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/hiebpf_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hiebpf_data/BUILD.gn index 6c5e9ce5..1355d2f8 100644 --- a/trace_streamer/src/protos/types/plugins/hiebpf_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hiebpf_data/BUILD.gn @@ -65,8 +65,8 @@ ohos_source_set("hiebpf_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":hiebpf_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hiebpf_include_config" ] @@ -78,8 +78,8 @@ ohos_source_set("hiebpf_data_cpp_standard") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":hiebpf_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hiebpf_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn index 95f8efd1..2fca3989 100644 --- a/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_hilog_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_hilog_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hilog_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hilog_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn index bd193a57..c815ddd0 100644 --- a/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn @@ -55,8 +55,8 @@ source_set("ts_hiperf_call_plugin_protos_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hiperf_call_plugin_protos_protoc" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hiperf_call_plugin_protos_config" ] diff --git a/trace_streamer/src/protos/types/plugins/hiperf_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hiperf_data/BUILD.gn index 8c6ec623..ba58d9eb 100644 --- a/trace_streamer/src/protos/types/plugins/hiperf_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hiperf_data/BUILD.gn @@ -63,8 +63,8 @@ ohos_source_set("ts_hiperf_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hiperf_data_protos_protoc" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hiperf_data_protos_config" ] @@ -76,8 +76,8 @@ ohos_source_set("ts_hiperf_data_cpp_standard") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hiperf_data_protos_protoc" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hiperf_data_protos_config" ] diff --git a/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn index 74f44618..37d81a6e 100644 --- a/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn @@ -60,7 +60,7 @@ action("ts_hisysevent_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -71,8 +71,8 @@ ohos_source_set("ts_hisysevent_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_hisysevent_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":hisysevent_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn b/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn index 526a8eaa..92036950 100644 --- a/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn @@ -58,7 +58,7 @@ action("ts_js_memory_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_js_memory_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_js_memory_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":js_memory_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn index d1ce0d06..c03435ec 100644 --- a/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn @@ -60,7 +60,7 @@ action("ts_memory_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -71,8 +71,8 @@ ohos_source_set("ts_memory_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_memory_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":memory_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn b/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn index 9acd79f4..3a307d49 100644 --- a/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn @@ -58,7 +58,7 @@ action("ts_native_hook_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_native_hook_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_native_hook_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":native_hook_include_config" ] @@ -81,8 +81,8 @@ ohos_source_set("native_hook_data_reader") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_native_hook_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":native_hook_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn index 9b505e83..02f7891c 100644 --- a/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_network_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_network_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_network_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":network_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn index ebff1491..f2147687 100644 --- a/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_process_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_process_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_process_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":process_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn index 55c1cec7..a81fb87e 100644 --- a/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn @@ -70,8 +70,8 @@ ohos_source_set("sample_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":sample_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":sample_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn index b57c1f23..b4a74b9c 100644 --- a/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn @@ -58,7 +58,7 @@ action("stream_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("stream_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":stream_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":stream_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn index 35deb954..88025bd7 100644 --- a/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn @@ -55,7 +55,7 @@ action("test_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -66,8 +66,8 @@ ohos_source_set("test_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":test_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":test_include_config" ] diff --git a/trace_streamer/src/protos/types/plugins/xpower_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/xpower_data/BUILD.gn index 08b7147d..a2ef2fcb 100644 --- a/trace_streamer/src/protos/types/plugins/xpower_data/BUILD.gn +++ b/trace_streamer/src/protos/types/plugins/xpower_data/BUILD.gn @@ -58,7 +58,7 @@ action("ts_xpower_data_cpp_gen") { args += rebase_path(sources, root_build_dir) if (!use_wasm && !is_test && !is_fuzz) { deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protoc(${host_toolchain})", "${SRC}/proto_reader/protoc_plugin:protoreader_plugin(${host_toolchain})", ] } @@ -69,8 +69,8 @@ ohos_source_set("ts_xpower_data_cpp") { part_name = "${OHOS_PROFILER_PART_NAME}" deps = [ ":ts_xpower_data_cpp_gen" ] public_deps = [ - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", - "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", ] include_dirs = [ "$proto_out_dir" ] public_configs = [ ":xpower_include_config" ] diff --git a/trace_streamer/src/table/BUILD.gn b/trace_streamer/src/table/BUILD.gn index eeff8ca2..57f2ade1 100644 --- a/trace_streamer/src/table/BUILD.gn +++ b/trace_streamer/src/table/BUILD.gn @@ -25,7 +25,7 @@ ohos_source_set("table") { "${SRC}/trace_data", "${SRC}/include", "${SRC}", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/bounds_checking_function/include", ] include_dirs += [ diff --git a/trace_streamer/src/table/base/BUILD.gn b/trace_streamer/src/table/base/BUILD.gn index 1fd1b595..8da96045 100644 --- a/trace_streamer/src/table/base/BUILD.gn +++ b/trace_streamer/src/table/base/BUILD.gn @@ -23,7 +23,7 @@ config("base_tables_cfg") { "${SRC}/include", "${SRC}", "${SRC}/cfg", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/bounds_checking_function/include", ] include_dirs += [ diff --git a/trace_streamer/src/trace_data/BUILD.gn b/trace_streamer/src/trace_data/BUILD.gn index d2b2664d..2ff80b08 100644 --- a/trace_streamer/src/trace_data/BUILD.gn +++ b/trace_streamer/src/trace_data/BUILD.gn @@ -78,7 +78,7 @@ ohos_source_set("trace_data") { "${SRC}/table/native_hook/include", "${SRC}/table/xpower/include", ".", - "${THIRD_PARTY}/protobuf/src", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/src", "${THIRD_PARTY}/bounds_checking_function/include", "${THIRD_PARTY}/json/single_include/nlohmann", "${THIRD_PARTY}/hiviewdfx/faultloggerd/interfaces/nonlinux", diff --git a/trace_streamer/src/version.cpp b/trace_streamer/src/version.cpp index 98b29dd9..dd009f81 100644 --- a/trace_streamer/src/version.cpp +++ b/trace_streamer/src/version.cpp @@ -17,7 +17,7 @@ namespace SysTuning { namespace TraceStreamer { size_t g_loadSize = 0; size_t g_fileSize = 0; -const std::string TRACE_STREAMER_VERSION = "4.3.5"; // version -const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/5/15"; // publish datetime +const std::string TRACE_STREAMER_VERSION = "4.3.6"; // version +const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/6/25"; // publish datetime } // namespace TraceStreamer } // namespace SysTuning diff --git a/trace_streamer/test/BUILD.gn b/trace_streamer/test/BUILD.gn index f5c7033b..925fe47a 100644 --- a/trace_streamer/test/BUILD.gn +++ b/trace_streamer/test/BUILD.gn @@ -92,13 +92,13 @@ if (is_test) { "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos/types/plugins/xpower_data:ts_xpower_data_cpp", "${SRC}/parser/hiperf_parser:libsec_static", "${SRC}/parser/rawtrace_parser:rawtrace_parser", - "${THIRD_PARTY}/googletest:gtest", - "${THIRD_PARTY}/googletest:gtest_main", - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", "../src:trace_streamer_source", "../src/parser/pbreader_parser:pbreader_parser_src", "../src/proto_reader:proto_reader", + "../src/protos:protobuf_lite_static", + "../src/protos:protobuf_static", + "unittest:gtest", + "unittest:gtest_main", ] public_configs = [] if (enable_stream_extend) { @@ -155,7 +155,6 @@ if (is_test) { cflags = [ "-Wno-inconsistent-missing-override", - "-Dprivate=public", #allow test code access private members "-Dprotected=public", #allow test code access protect members "-fprofile-arcs", "-ftest-coverage", diff --git a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn index 4cf45f43..23335c39 100644 --- a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn +++ b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn @@ -13,6 +13,7 @@ #####################hydra-fuzz################### import("//build/ohos.gni") +import("//build/ts.gni") import("../../../build/test.gni") import("../../test_ts.gni") @@ -60,8 +61,8 @@ ohos_fuzztest("ts_bytrace_fuzz_test") { "--coverage", ] deps = [ - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", "../../../src:trace_streamer_source", "../../../src/proto_reader:proto_reader", ] diff --git a/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn index e5addf28..a7ef31ac 100644 --- a/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn +++ b/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn @@ -13,6 +13,7 @@ #####################hydra-fuzz################### import("//build/ohos.gni") +import("//build/ts.gni") import("../../../build/test.gni") import("../../test_ts.gni") @@ -60,8 +61,8 @@ ohos_fuzztest("ts_htrace_fuzz_test") { "--coverage", ] deps = [ - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", "../../../src:trace_streamer_source", "../../../src/proto_reader:proto_reader", ] diff --git a/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn index 72aa3a6c..92dc84b0 100644 --- a/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn +++ b/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn @@ -13,6 +13,7 @@ #####################hydra-fuzz################### import("//build/ohos.gni") +import("//build/ts.gni") import("../../../build/test.gni") import("../../test_ts.gni") @@ -60,8 +61,8 @@ ohos_fuzztest("ts_selector_fuzz_test") { "--coverage", ] deps = [ - "${THIRD_PARTY}/protobuf:protobuf_lite_static", - "${THIRD_PARTY}/protobuf:protobuf_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_lite_static", + "${OHOS_TRACE_STREAMER_PROTOS_DIR}/protos:protobuf_static", "../../../src:trace_streamer_source", "../../../src/proto_reader:proto_reader", ] diff --git a/trace_streamer/test/unittest/BUILD.gn b/trace_streamer/test/unittest/BUILD.gn new file mode 100644 index 00000000..4bdaa737 --- /dev/null +++ b/trace_streamer/test/unittest/BUILD.gn @@ -0,0 +1,159 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. +# 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. + +THIRD_PARTY = "//third_party" + +# for third part googletest +config("gtest_private_config") { + visibility = [ ":*" ] + include_dirs = [ "${THIRD_PARTY}/googletest/googletest" ] +} + +config("gtest_config") { + include_dirs = [ "${THIRD_PARTY}/googletest/googletest/include" ] + cflags_cc = [ + "-std=c++17", + "-Wno-float-equal", + "-Wno-sign-compare", + "-Wno-reorder-init-list", + ] + if (is_mingw) { + cflags_cc += [ + "-Wno-unused-const-variable", + "-Wno-unused-private-field", + ] + } +} + +sources_files = [ + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-death-test.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-matchers.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-message.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-param-test.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-printers.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-test-part.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-typed-test.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest_pred_impl.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest_prod.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/hwext/gtest-ext.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/hwext/gtest-filter.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/hwext/gtest-multithread.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/hwext/gtest-tag.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/hwext/utils.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/custom/gtest-port.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/custom/gtest-printers.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/custom/gtest.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-death-test-internal.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-filepath.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-internal.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-param-util.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-port-arch.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-port.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-string.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/internal/gtest-type-util.h", + "${THIRD_PARTY}/googletest/googletest/src/gtest-all.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-assertion-result.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-death-test.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-filepath.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-internal-inl.h", + "${THIRD_PARTY}/googletest/googletest/src/gtest-matchers.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-port.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-printers.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-test-part.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest-typed-test.cc", + "${THIRD_PARTY}/googletest/googletest/src/gtest.cc", + "${THIRD_PARTY}/googletest/googletest/src/hwext/gtest-ext.cc", + "${THIRD_PARTY}/googletest/googletest/src/hwext/gtest-filter.cc", + "${THIRD_PARTY}/googletest/googletest/src/hwext/gtest-multithread.cpp", + "${THIRD_PARTY}/googletest/googletest/src/hwext/gtest-tag.cc", + "${THIRD_PARTY}/googletest/googletest/src/hwext/gtest-utils.cc", +] + +static_library("gtest") { + testonly = true + public = [ + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest-spi.h", + "${THIRD_PARTY}/googletest/googletest/include/gtest/gtest.h", + ] + + sources = sources_files + sources -= [ "${THIRD_PARTY}/googletest/googletest/src/gtest-all.cc" ] + public_configs = [ ":gtest_config" ] + configs += [ ":gtest_private_config" ] +} + +static_library("gtest_main") { + testonly = true + sources = [ "${THIRD_PARTY}/googletest/googletest/src/gtest_main.cc" ] + public_deps = [ ":gtest" ] +} + +config("gmock_private_config") { + visibility = [ ":*" ] + include_dirs = [ "${THIRD_PARTY}/googletest/googlemock" ] +} + +config("gmock_config") { + include_dirs = [ "${THIRD_PARTY}/googletest/googlemock/include" ] + + cflags_cc = [ + # The MOCK_METHODn() macros do not specify "override", which triggers this + # warning in users: "error: 'Method' overrides a member function but is not + # marked 'override' [-Werror,-Winconsistent-missing-override]". Suppress + # these warnings until https://github.com/google/googletest/issues/533 is + # fixed. + "-Wno-inconsistent-missing-override", + ] +} + +gmock_sources_files = [ + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-actions.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-cardinalities.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-function-mocker.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-matchers.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-more-actions.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-more-matchers.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-nice-strict.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock-spec-builders.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/custom/gmock-generated-actions.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/custom/gmock-matchers.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/custom/gmock-port.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/gmock-internal-utils.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/gmock-port.h", + "${THIRD_PARTY}/googletest/googlemock/include/gmock/internal/gmock-pp.h", + "${THIRD_PARTY}/googletest/googlemock/src/gmock-all.cc", + "${THIRD_PARTY}/googletest/googlemock/src/gmock-cardinalities.cc", + "${THIRD_PARTY}/googletest/googlemock/src/gmock-internal-utils.cc", + "${THIRD_PARTY}/googletest/googlemock/src/gmock-matchers.cc", + "${THIRD_PARTY}/googletest/googlemock/src/gmock-spec-builders.cc", + "${THIRD_PARTY}/googletest/googlemock/src/gmock.cc", +] + +static_library("gmock") { + testonly = true + public = [ "${THIRD_PARTY}/googletest/googlemock/include/gmock/gmock.h" ] + sources = gmock_sources_files + sources -= [ "${THIRD_PARTY}/googletest/googlemock/src/gmock-all.cc" ] + public_configs = [ ":gmock_config" ] + configs += [ ":gmock_private_config" ] + deps = [ ":gtest" ] +} + +static_library("gmock_main") { + testonly = true + sources = [ "${THIRD_PARTY}/googletest/googlemock/src/gmock_main.cc" ] + public_deps = [ + ":gmock", + ":gtest", + ] +} diff --git a/trace_streamer/test/unittest/base/export_test.cpp b/trace_streamer/test/unittest/base/export_test.cpp index cd958448..80ce3e3d 100644 --- a/trace_streamer/test/unittest/base/export_test.cpp +++ b/trace_streamer/test/unittest/base/export_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "export_test.h" #include "file.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/ebpf/bio_parser_test.cpp b/trace_streamer/test/unittest/ebpf/bio_parser_test.cpp index f3b3a39d..d69203e4 100644 --- a/trace_streamer/test/unittest/ebpf/bio_parser_test.cpp +++ b/trace_streamer/test/unittest/ebpf/bio_parser_test.cpp @@ -15,6 +15,7 @@ */ #include #include +#define private public #include "bio_latency_data_parser.h" #include "cpu_filter.h" #include "ebpf_data_parser.h" diff --git a/trace_streamer/test/unittest/ebpf/ebpf_file_system_test.cpp b/trace_streamer/test/unittest/ebpf/ebpf_file_system_test.cpp index 8a961f7a..1e428ff1 100644 --- a/trace_streamer/test/unittest/ebpf/ebpf_file_system_test.cpp +++ b/trace_streamer/test/unittest/ebpf/ebpf_file_system_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "ebpf_data_parser.h" #include "ebpf_stdtype.h" #include "process_filter.h" diff --git a/trace_streamer/test/unittest/ebpf/ebpf_parser_test.cpp b/trace_streamer/test/unittest/ebpf/ebpf_parser_test.cpp index 028f8bb3..948d9645 100644 --- a/trace_streamer/test/unittest/ebpf/ebpf_parser_test.cpp +++ b/trace_streamer/test/unittest/ebpf/ebpf_parser_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "ebpf_data_parser.h" #include "ebpf_stdtype.h" #include "pbreader_file_header.h" diff --git a/trace_streamer/test/unittest/ebpf/paged_memory_parser_test.cpp b/trace_streamer/test/unittest/ebpf/paged_memory_parser_test.cpp index 4a52108f..7092b1b6 100644 --- a/trace_streamer/test/unittest/ebpf/paged_memory_parser_test.cpp +++ b/trace_streamer/test/unittest/ebpf/paged_memory_parser_test.cpp @@ -15,6 +15,7 @@ */ #include #include +#define private public #include "paged_memory_data_parser.h" #include "cpu_filter.h" #include "ebpf_data_parser.h" diff --git a/trace_streamer/test/unittest/filter/animation_filter_test.cpp b/trace_streamer/test/unittest/filter/animation_filter_test.cpp index ffa002a0..34b8ccdf 100644 --- a/trace_streamer/test/unittest/filter/animation_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/animation_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "animation_filter.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/filter/app_start_filter_test.cpp b/trace_streamer/test/unittest/filter/app_start_filter_test.cpp index 2a88745b..9fbaf4c2 100644 --- a/trace_streamer/test/unittest/filter/app_start_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/app_start_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "app_start_filter.h" #include "ptreader_parser.h" #include "slice_filter.h" diff --git a/trace_streamer/test/unittest/filter/binder_filter_test.cpp b/trace_streamer/test/unittest/filter/binder_filter_test.cpp index 158f3ddd..2f4896a9 100644 --- a/trace_streamer/test/unittest/filter/binder_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/binder_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "args_filter.h" #include "binder_filter.h" #include "process_filter.h" diff --git a/trace_streamer/test/unittest/filter/clock_filter_test.cpp b/trace_streamer/test/unittest/filter/clock_filter_test.cpp index ff65f783..08afc955 100644 --- a/trace_streamer/test/unittest/filter/clock_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/clock_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "clock_filter_ex.h" #include "trace_data_cache.h" #include "trace_streamer_filters.h" diff --git a/trace_streamer/test/unittest/filter/cpu_filter_test.cpp b/trace_streamer/test/unittest/filter/cpu_filter_test.cpp index 427fc730..e2916d61 100644 --- a/trace_streamer/test/unittest/filter/cpu_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/cpu_filter_test.cpp @@ -16,8 +16,10 @@ #include #include +#define private public #include "cpu_filter.h" #include "process_filter.h" +#include "trace_streamer_selector.h" #include "ts_common.h" using namespace testing::ext; @@ -28,15 +30,13 @@ class CpuFilterTest : public ::testing::Test { public: void SetUp() { - streamFilters_.cpuFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); - streamFilters_.processFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + stream_.InitFilter(); } void TearDown() {} public: - TraceStreamerFilters streamFilters_; - TraceDataCache traceDataCache_; + TraceStreamerSelector stream_; }; /** @@ -50,11 +50,11 @@ HWTEST_F(CpuFilterTest, CpufilterInsertWakeupTest, TestSize.Level1) /* InsertWakeupEvent ts, internalTid */ uint64_t ts1 = 168758662877000; uint64_t itid = 1; - streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); // 1st waking + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(ts1, itid); // 1st waking - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state only + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 0); // 0 thread state only } /** @@ -72,14 +72,16 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTest, TestSize.Level1) uint64_t itidNext = 3; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch - printf("state of pre itid: %" PRIu64 "\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %" PRIu64 "\n", + stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre)); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 2); // 2 thread state } /** @@ -97,14 +99,16 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchFromZeroThread, TestSize.Level1) uint64_t itidNext = 3; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch - printf("state of pre itid: %" PRIu64 "\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %" PRIu64 "\n", + stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre)); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INVALID); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 1); // 1 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INVALID); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 1); // 1 thread state } /** @@ -122,14 +126,16 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchToZeroThread, TestSize.Level1) uint64_t itidNext = 0; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch - printf("state of pre itid: %" PRIu64 "\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %" PRIu64 "\n", + stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre)); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_INVALID); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == INVALID_UINT64); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 1); // 1 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_INVALID); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == INVALID_UINT64); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 1); // 1 thread state } /** @@ -147,14 +153,15 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchDoubleThread, TestSize.Level1) uint64_t itidNext = 3; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 2); // 2 thread state ts1 = 168758663017000; itidPre = 3; @@ -162,13 +169,14 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchDoubleThread, TestSize.Level1) cpu = 0; itidNext = 4; nextPior = 120; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 2nd switch - - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 4); // 4 thread state + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 2nd switch + + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 4); // 4 thread state } /** @@ -186,14 +194,15 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchThreeThread, TestSize.Level1) uint64_t itidNext = 3; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 2); // 2 thread state ts1 = 168758663017000; itidPre = 3; @@ -201,13 +210,13 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchThreeThread, TestSize.Level1) cpu = 0; itidNext = 2; nextPior = 120; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, - INVALID_DATAINDEX); // 2nd switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, + INVALID_DATAINDEX); // 2nd switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 4); // 4 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 4); // 4 thread state } /** @@ -225,13 +234,14 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTestZero, TestSize.Level1) uint64_t itidNext = 3; uint64_t nextPior = 124; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, - INVALID_DATAINDEX); // 1st switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, + nextPior, + INVALID_DATAINDEX); // 1st switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 2); // 2 thread state ts1 = 168758663017000; itidPre = 0; @@ -239,12 +249,12 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTestZero, TestSize.Level1) cpu = 0; itidNext = 4; nextPior = 120; - streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, - INVALID_DATAINDEX); // 2nd switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, + INVALID_DATAINDEX); // 2nd switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 3); // 4 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 3); // 4 thread state } /** @@ -258,11 +268,11 @@ HWTEST_F(CpuFilterTest, CpufiltertWakeingTest, TestSize.Level1) uint64_t ts1 = 168758662919000; uint64_t itid = 2; - streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(ts1, itid); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 0); // 0 thread state } /** @@ -276,14 +286,14 @@ HWTEST_F(CpuFilterTest, CpufiltertWakingTwice, TestSize.Level1) uint64_t ts1 = 168758662919000; uint64_t itid = 2; - streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(ts1, itid); ts1 = 168758662929000; itid = 4; - streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(ts1, itid); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 0); // 0 thread state } /** @@ -296,60 +306,60 @@ HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTestFull, TestSize.Level1) TS_LOGI("test4-10"); /* InsertWakeupEvent ts, internalTid */ /* InsertSwitchEvent ts, cpu, prevPid, prevPior, prevState, nextPid, nextPior */ - streamFilters_.cpuFilter_->InsertWakeupEvent(168758662877000, 1); // 1st waking + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(168758662877000, 1); // 1st waking - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(1) == INVALID_UINT64); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INVALID); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state only + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(1) == INVALID_UINT64); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INVALID); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 0); // 0 thread state only - streamFilters_.cpuFilter_->InsertSwitchEvent(168758662919000, 0, 1, 120, TASK_INTERRUPTIBLE, 2, 124, - INVALID_DATAINDEX); // 1st switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(168758662919000, 0, 1, 120, TASK_INTERRUPTIBLE, 2, 124, + INVALID_DATAINDEX); // 1st switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 0); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(2) == 0); // 2 thread state, the waking event add a runnable state - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); - streamFilters_.cpuFilter_->InsertSwitchEvent(168758663017000, 0, 0, 120, TASK_RUNNABLE, 4, 120, - INVALID_DATAINDEX); // 2nd switch + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 2); + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(168758663017000, 0, 0, 120, TASK_RUNNABLE, 4, 120, + INVALID_DATAINDEX); // 2nd switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(4) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(4) == 2); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 3); // 4 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(4) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(4) == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 3); // 4 thread state - streamFilters_.cpuFilter_->InsertWakeupEvent(168758663078000, 0); // 2nd waking + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(168758663078000, 0); // 2nd waking - streamFilters_.cpuFilter_->InsertWakeupEvent(168758663092000, 0); // 3rd waking + stream_.streamFilters_->cpuFilter_->InsertWakeupEvent(168758663092000, 0); // 3rd waking - streamFilters_.cpuFilter_->InsertSwitchEvent(168758663107000, 0, 2, 124, TASK_RUNNABLE, 5, 98, - INVALID_DATAINDEX); // 3rd switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(168758663107000, 0, 2, 124, TASK_RUNNABLE, 5, 98, + INVALID_DATAINDEX); // 3rd switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNABLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(5) == 3); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 4); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 5); // 6 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNABLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(5) == 3); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(2) == 4); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 5); // 6 thread state - streamFilters_.cpuFilter_->InsertSwitchEvent(168758663126000, 0, 5, 98, TASK_INTERRUPTIBLE, 2, 124, - INVALID_DATAINDEX); // 4th switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_INTERRUPTIBLE); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 5); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(5) == 6); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 7); // 8 thread state + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(168758663126000, 0, 5, 98, TASK_INTERRUPTIBLE, 2, 124, + INVALID_DATAINDEX); // 4th switch + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(2) == 5); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(5) == 6); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 7); // 8 thread state - streamFilters_.cpuFilter_->InsertSwitchEvent(168758663136000, 3, 5, 120, TASK_RUNNABLE, 6, 120, - INVALID_DATAINDEX); // 5th switch + stream_.streamFilters_->cpuFilter_->InsertSwitchEvent(168758663136000, 3, 5, 120, TASK_RUNNABLE, 6, 120, + INVALID_DATAINDEX); // 5th switch - EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(6) == TASK_RUNNING); - EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(6) == 7); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 9); // 10 thread state + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->StateOfInternalTidInStateTable(6) == TASK_RUNNING); + EXPECT_TRUE(stream_.streamFilters_->cpuFilter_->RowOfInternalTidInStateTable(6) == 7); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->Size() == 9); // 10 thread state // after 3rd switch - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[1] == INVALID_UINT64); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->DursData()[1] == INVALID_UINT64); // after 4th switch - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[6] == 168758663136000 - 168758663126000); - EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[7] == INVALID_UINT64); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->DursData()[6] == 168758663136000 - 168758663126000); + EXPECT_TRUE(stream_.traceDataCache_->GetThreadStateData()->DursData()[7] == INVALID_UINT64); } } // namespace TraceStreamer } // namespace SysTuning diff --git a/trace_streamer/test/unittest/filter/filter_filter_test.cpp b/trace_streamer/test/unittest/filter/filter_filter_test.cpp index 22b08e3f..f2352361 100644 --- a/trace_streamer/test/unittest/filter/filter_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/filter_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "filter_filter.h" #include "trace_data_cache.h" #include "trace_streamer_filters.h" diff --git a/trace_streamer/test/unittest/filter/frame_filter_test.cpp b/trace_streamer/test/unittest/filter/frame_filter_test.cpp index 75aca69d..dfbbe619 100644 --- a/trace_streamer/test/unittest/filter/frame_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/frame_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "frame_filter.h" #include "process_filter.h" #include "trace_streamer_selector.h" @@ -72,9 +73,11 @@ HWTEST_F(FrameFilterTest, AppVsyncNoFrameNum, TestSize.Level1) CALLSTACK_SLICE_ID); const uint64_t END_TS = 10; auto res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, itid); + EXPECT_TRUE(res); + res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, itid); EXPECT_FALSE(res); - EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[0], 2); // actural frame, no frameNum - EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[1], 2); // expect frame, no frameNum + EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[0], 0); // actural frame, no frameNum + EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[1], INVALID_UINT8); // expect frame, no frameNum EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->TimeStampData()[0], START_TS); // actural frame EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->TimeStampData()[1], EXPECTED_START); // expect frame EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Durs()[0], END_TS - START_TS); // actural frame @@ -350,28 +353,30 @@ HWTEST_F(FrameFilterTest, SliceFromAppToRS, TestSize.Level1) stream_.traceDataCache_->GetFrameSliceData()->IdsData()[0]); } -HWTEST_F(FrameFilterTest, AppUVTraceNoVsyncIdAndFrameNum, TestSize.Level1) +HWTEST_F(FrameFilterTest, AppParallelTraceNoVsyncIdAndFrameNum, TestSize.Level1) { TS_LOGI("test6-9"); // no vsyncId and frameNum - // app ---------------H:UVTrace------------------End---uint64_t ts, + // app ---------------H:ParallelTrace------------------End---uint64_t ts, BytraceLine line = {START_TS, TID1}; line.tgid = PID1; auto itid = stream_.streamFilters_->processFilter_->GetOrCreateThreadWithPid(TID1, PID1); - stream_.streamFilters_->frameFilter_->BeginUVTraceEvent(line, CALLSTACK_SLICE_ID); + // BeginParallelTraceEvent 用于开始一个并发/并行的追踪事件 + // BeginUVTraceEvent 用于开始一个普通的追踪事件(函数没有)---- + stream_.streamFilters_->frameFilter_->BeginParallelTraceEvent(line, CALLSTACK_SLICE_ID); const uint64_t END_TS = 10; auto res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, itid); - EXPECT_FALSE(res); - EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[0], INVALID_DATA); // actural frame, no frameNum + EXPECT_TRUE(res); + EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[0], 0); // actural frame, no frameNum EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->TimeStampData()[0], START_TS); // actural frame EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Durs()[0], END_TS - START_TS); // actural frame } -HWTEST_F(FrameFilterTest, AppUVTraceNoFrameNum, TestSize.Level1) +HWTEST_F(FrameFilterTest, AppParallelTraceNoFrameNum, TestSize.Level1) { TS_LOGI("test6-10"); // no frameNum - // app ---------------H:UVTrace------------------End---uint64_t ts, + // app ---------------H:ParallelTrace------------------End---uint64_t ts, BytraceLine mainThreadLine = {0, PID1}; mainThreadLine.tgid = PID1; const uint64_t SON_START_TS = 6; @@ -381,24 +386,25 @@ HWTEST_F(FrameFilterTest, AppUVTraceNoFrameNum, TestSize.Level1) auto itid = stream_.streamFilters_->processFilter_->GetOrCreateThreadWithPid(TID1, PID1); stream_.streamFilters_->frameFilter_->BeginVsyncEvent(mainThreadLine, EXPECTED_START, EXPECTED_END, VSYNC_ID, CALLSTACK_SLICE_ID); - stream_.streamFilters_->frameFilter_->BeginUVTraceEvent(line, CALLSTACK_SLICE_ID); - stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID); + stream_.streamFilters_->frameFilter_->BeginParallelTraceEvent(line, CALLSTACK_SLICE_ID); + uint64_t timeId = 0; + stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID, timeId); const uint64_t SON_END_TS = 9; auto res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(SON_END_TS, itid); - EXPECT_FALSE(res); + EXPECT_TRUE(res); const uint64_t END_TS = 10; res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, mainThreadId); - EXPECT_FALSE(res); + EXPECT_TRUE(res); EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[SON_THREAD_DATA_INDEX], - INVALID_DATA); // actural frame, no frameNum + 0); // actural frame, no frameNum EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Durs()[SON_THREAD_DATA_INDEX], SON_END_TS - SON_START_TS); // actural frame } -HWTEST_F(FrameFilterTest, AppUVTraceNormal, TestSize.Level1) +HWTEST_F(FrameFilterTest, AppParallelTraceNormal, TestSize.Level1) { TS_LOGI("test6-11"); - // app ---------------H:UVTrace------------------End---uint64_t ts, + // app ---------------H:ParallelTrace------------------End---uint64_t ts, const uint64_t SON_START_TS = 6; BytraceLine line = {SON_START_TS, TID1}; line.tgid = PID1; @@ -408,8 +414,9 @@ HWTEST_F(FrameFilterTest, AppUVTraceNormal, TestSize.Level1) auto mainThreadId = stream_.streamFilters_->processFilter_->GetOrCreateThreadWithPid(PID1, PID1); stream_.streamFilters_->frameFilter_->BeginVsyncEvent(mainThreadLine, EXPECTED_START, EXPECTED_END, VSYNC_ID, CALLSTACK_SLICE_ID2); - stream_.streamFilters_->frameFilter_->BeginUVTraceEvent(line, CALLSTACK_SLICE_ID2); - stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID); + stream_.streamFilters_->frameFilter_->BeginParallelTraceEvent(line, CALLSTACK_SLICE_ID2); + uint64_t timeId = 0; + stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID, timeId); const uint32_t FRAME_NUM = 1; stream_.streamFilters_->frameFilter_->BeginRSTransactionData(sonThreadId, FRAME_NUM, mainThreadId); const uint64_t SON_END_TS = 8; @@ -417,14 +424,14 @@ HWTEST_F(FrameFilterTest, AppUVTraceNormal, TestSize.Level1) EXPECT_TRUE(res); const uint64_t END_TS = 9; res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, mainThreadId); - EXPECT_FALSE(res); + EXPECT_TRUE(res); EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[SON_THREAD_DATA_INDEX], 0); // actural frame, no frameNum EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Durs()[SON_THREAD_DATA_INDEX], SON_END_TS - SON_START_TS); // actural frame } -HWTEST_F(FrameFilterTest, AppUVTraceTimeout, TestSize.Level1) +HWTEST_F(FrameFilterTest, AppParallelTraceTimeout, TestSize.Level1) { TS_LOGI("test6-12"); // app subthread actual frame timeout @@ -438,8 +445,9 @@ HWTEST_F(FrameFilterTest, AppUVTraceTimeout, TestSize.Level1) auto mainThreadId = stream_.streamFilters_->processFilter_->GetOrCreateThreadWithPid(PID1, PID1); stream_.streamFilters_->frameFilter_->BeginVsyncEvent(mainThreadLine, EXPECTED_START, EXPECTED_END, VSYNC_ID, CALLSTACK_SLICE_ID); - stream_.streamFilters_->frameFilter_->BeginUVTraceEvent(line, CALLSTACK_SLICE_ID2); - stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID); + stream_.streamFilters_->frameFilter_->BeginParallelTraceEvent(line, CALLSTACK_SLICE_ID2); + uint64_t timeId = 0; + stream_.streamFilters_->frameFilter_->UpdateVsyncId(line, VSYNC_ID, timeId); const uint32_t FRAME_NUM = 2; stream_.streamFilters_->frameFilter_->BeginRSTransactionData(sonThreadId, FRAME_NUM, mainThreadId); const uint64_t SON_END_TS = 11; @@ -447,7 +455,7 @@ HWTEST_F(FrameFilterTest, AppUVTraceTimeout, TestSize.Level1) EXPECT_TRUE(res); const uint64_t END_TS = 9; res = stream_.streamFilters_->frameFilter_->EndVsyncEvent(END_TS, mainThreadId); - EXPECT_FALSE(res); + EXPECT_TRUE(res); EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Flags()[SON_THREAD_DATA_INDEX], 1); // actural frame, no frameNum EXPECT_EQ(stream_.traceDataCache_->GetFrameSliceData()->Durs()[SON_THREAD_DATA_INDEX], diff --git a/trace_streamer/test/unittest/filter/irq_filter_test.cpp b/trace_streamer/test/unittest/filter/irq_filter_test.cpp index 6fc2c37e..e47315b8 100644 --- a/trace_streamer/test/unittest/filter/irq_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/irq_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "args_filter.h" #include "irq_filter.h" #include "slice_filter.h" diff --git a/trace_streamer/test/unittest/filter/measure_filter_test.cpp b/trace_streamer/test/unittest/filter/measure_filter_test.cpp index e9c3ccab..b7b7527a 100644 --- a/trace_streamer/test/unittest/filter/measure_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/measure_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "filter_filter.h" #include "measure_filter.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/filter/process_filter_test.cpp b/trace_streamer/test/unittest/filter/process_filter_test.cpp index 915b053f..d02d3a1a 100644 --- a/trace_streamer/test/unittest/filter/process_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/process_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "process_filter.h" using namespace testing::ext; diff --git a/trace_streamer/test/unittest/filter/slice_filter_test.cpp b/trace_streamer/test/unittest/filter/slice_filter_test.cpp index 80c280a3..066467d9 100644 --- a/trace_streamer/test/unittest/filter/slice_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/slice_filter_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "filter_filter.h" #include "measure_filter.h" #include "process_filter.h" diff --git a/trace_streamer/test/unittest/filter/task_pool_filter_test.cpp b/trace_streamer/test/unittest/filter/task_pool_filter_test.cpp index 7717739c..48e0d9ab 100644 --- a/trace_streamer/test/unittest/filter/task_pool_filter_test.cpp +++ b/trace_streamer/test/unittest/filter/task_pool_filter_test.cpp @@ -17,6 +17,8 @@ #include #include +#define private public +#include "config_filter.h" #include "print_event_parser.h" #include "task_pool_filter.h" #include "trace_streamer_filters.h" @@ -30,6 +32,7 @@ public: void SetUp() { stream_.InitFilter(); + stream_.streamFilters_->configFilter_->switchConfig_.taskPoolConfigEnabled_ = true; } void TearDown() {} diff --git a/trace_streamer/test/unittest/interface/rpc_server_test.cpp b/trace_streamer/test/unittest/interface/rpc_server_test.cpp index 9f0b08d4..ca01ce7c 100644 --- a/trace_streamer/test/unittest/interface/rpc_server_test.cpp +++ b/trace_streamer/test/unittest/interface/rpc_server_test.cpp @@ -16,6 +16,8 @@ #include #include +#define private public +#include "config_filter.h" #include "rpc/rpc_server.h" #include "print_event_parser.h" @@ -108,7 +110,7 @@ HWTEST_F(RpcServerTest, ParserConfig, TestSize.Level1) RpcServer rpcServer; auto ret = rpcServer.ParserConfig(json); - EXPECT_EQ(rpcServer.ts_->traceDataCache_->taskPoolTraceEnabled_, true); + EXPECT_EQ(rpcServer.ts_->streamFilters_->configFilter_->switchConfig_.taskPoolConfigEnabled_, true); PrintEventParser printEvent(rpcServer.ts_->traceDataCache_.get(), rpcServer.ts_->streamFilters_.get()); printEvent.ParsePrintEvent(comm, ts, pid, event, line); auto res = rpcServer.ts_->traceDataCache_->GetConstTaskPoolData().prioritys_[0]; diff --git a/trace_streamer/test/unittest/interface/split_file_data_test.cpp b/trace_streamer/test/unittest/interface/split_file_data_test.cpp index 4fc29d82..3b4ef060 100644 --- a/trace_streamer/test/unittest/interface/split_file_data_test.cpp +++ b/trace_streamer/test/unittest/interface/split_file_data_test.cpp @@ -20,6 +20,7 @@ #include #include +#define private public #include "ptreader_parser.h" #include "file.h" #include "pbreader_parser.h" diff --git a/trace_streamer/test/unittest/interface/wasm_func_test.cpp b/trace_streamer/test/unittest/interface/wasm_func_test.cpp index d16c3e47..8bc7856a 100644 --- a/trace_streamer/test/unittest/interface/wasm_func_test.cpp +++ b/trace_streamer/test/unittest/interface/wasm_func_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "rpc/rpc_server.h" #include "wasm_func.cpp" diff --git a/trace_streamer/test/unittest/pbreader/parser_pbreader_test.cpp b/trace_streamer/test/unittest/pbreader/parser_pbreader_test.cpp index c33541d5..ca6156a2 100644 --- a/trace_streamer/test/unittest/pbreader/parser_pbreader_test.cpp +++ b/trace_streamer/test/unittest/pbreader/parser_pbreader_test.cpp @@ -20,6 +20,7 @@ #include #include +#define private public #include "file.h" #include "trace_streamer_selector.h" constexpr size_t G_FILE_PERMISSION = 664; diff --git a/trace_streamer/test/unittest/pbreader/proto_reader_test.cpp b/trace_streamer/test/unittest/pbreader/proto_reader_test.cpp index 55c754b5..6c2de741 100644 --- a/trace_streamer/test/unittest/pbreader/proto_reader_test.cpp +++ b/trace_streamer/test/unittest/pbreader/proto_reader_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "file.h" #include "test.pb.h" #include "test.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/arkts/js_cpu_profiler_test.cpp b/trace_streamer/test/unittest/pbreader_parser/arkts/js_cpu_profiler_test.cpp index bad6a084..ac06a8f8 100644 --- a/trace_streamer/test/unittest/pbreader_parser/arkts/js_cpu_profiler_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/arkts/js_cpu_profiler_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "file.h" #include "arkts/pbreader_js_memory_parser.h" #include "arkts/pbreader_js_cpu_profiler_parser.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/arkts/js_memory_test.cpp b/trace_streamer/test/unittest/pbreader_parser/arkts/js_memory_test.cpp index 491cad4b..5e36509f 100644 --- a/trace_streamer/test/unittest/pbreader_parser/arkts/js_memory_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/arkts/js_memory_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "file.h" #include "arkts/pbreader_js_memory_parser.h" #include "js_heap_config.pb.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/diskio_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/diskio_parser_test.cpp index f253ed09..5675865f 100644 --- a/trace_streamer/test/unittest/pbreader_parser/diskio_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/diskio_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "diskio_plugin_result.pb.h" #include "diskio_plugin_result.pbreader.h" #include "disk_io_parser/pbreader_disk_io_parser.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/hidump_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/hidump_parser_test.cpp index f736f33a..7892a0dd 100644 --- a/trace_streamer/test/unittest/pbreader_parser/hidump_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/hidump_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "hidump_parser/pbreader_hidump_parser.h" #include "hidump_plugin_result.pb.h" #include "hidump_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/hilog_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/hilog_parser_test.cpp index 3066d358..676a63fe 100644 --- a/trace_streamer/test/unittest/pbreader_parser/hilog_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/hilog_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "hilog_parser/pbreader_hilog_parser.h" #include "hilog_plugin_result.pb.h" #include "hilog_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/hisys_event_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/hisys_event_parser_test.cpp index 0a9538f7..4666be79 100644 --- a/trace_streamer/test/unittest/pbreader_parser/hisys_event_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/hisys_event_parser_test.cpp @@ -15,6 +15,7 @@ #include #include +#define private public #include "hi_sysevent_filter/hi_sysevent_measure_filter.h" #include "hisysevent_parser/pbreader_hisysevent_parser.h" #include "string_to_numerical.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/htrace_binder_event_test.cpp b/trace_streamer/test/unittest/pbreader_parser/htrace_binder_event_test.cpp index 8bffa736..4f105262 100644 --- a/trace_streamer/test/unittest/pbreader_parser/htrace_binder_event_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/htrace_binder_event_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "binder_filter.h" #include "htrace_cpu_detail_parser.h" #include "trace_plugin_result.pb.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/htrace_cpu_detail_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/htrace_cpu_detail_parser_test.cpp index 9f47219a..fd66f196 100644 --- a/trace_streamer/test/unittest/pbreader_parser/htrace_cpu_detail_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/htrace_cpu_detail_parser_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "htrace_cpu_detail_parser.h" #include "power.pb.h" #include "stat_filter.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/htrace_event_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/htrace_event_parser_test.cpp index d2bd248e..6d5f691c 100644 --- a/trace_streamer/test/unittest/pbreader_parser/htrace_event_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/htrace_event_parser_test.cpp @@ -18,6 +18,8 @@ #include #include +#define private public +#include "config_filter.h" #include "cpu_filter.h" #include "htrace_cpu_detail_parser.h" #include "parser/common_types.h" @@ -42,6 +44,7 @@ public: void SetUp() { stream_.InitFilter(); + stream_.streamFilters_->configFilter_->switchConfig_.UpdateSyscallsTsSet("145;146;147"); } void TearDown() {} diff --git a/trace_streamer/test/unittest/pbreader_parser/htrace_irq_event_test.cpp b/trace_streamer/test/unittest/pbreader_parser/htrace_irq_event_test.cpp index fa1ca6fd..9795759e 100644 --- a/trace_streamer/test/unittest/pbreader_parser/htrace_irq_event_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/htrace_irq_event_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "htrace_cpu_detail_parser.h" #include "irq_filter.h" #include "trace_plugin_result.pb.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/native_memory/native_hook_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/native_memory/native_hook_parser_test.cpp index 374e1863..95872457 100644 --- a/trace_streamer/test/unittest/pbreader_parser/native_memory/native_hook_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/native_memory/native_hook_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "export_test.h" #include "file.h" #include "native_hook_parser/pbreader_native_hook_parser.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_cpu_data_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_cpu_data_parser_test.cpp index 66ad4874..fe2c3c7f 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_cpu_data_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_cpu_data_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "cpu_plugin_result.pb.h" #include "cpu_plugin_result.pbreader.h" #include "cpu_data_parser/pbreader_cpu_data_parser.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_ffrt_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_ffrt_parser_test.cpp index fa65495b..0549dedb 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_ffrt_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_ffrt_parser_test.cpp @@ -15,6 +15,7 @@ #include #include +#define private public #include "export_test.h" #include "ffrt_profiler_config.pb.h" #include "ffrt_profiler_result.pb.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_mem_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_mem_parser_test.cpp index 89fca1f1..69e0bf5d 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_mem_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_mem_parser_test.cpp @@ -19,6 +19,7 @@ #include #include +#define private public #include "memory_plugin_result.pb.h" #include "mem_parser/pbreader_mem_parser.h" #include "memory_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_network_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_network_parser_test.cpp index 31f14497..30bc7c85 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_network_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_network_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "network_parser/pbreader_network_parser.h" #include "network_plugin_result.pb.h" #include "network_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_process_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_process_parser_test.cpp index 128ac280..d1cdd630 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_process_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_process_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "process_parser/pbreader_process_parser.h" #include "parser/ptreader_parser/ptreader_parser.h" #include "parser/common_types.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_mem_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_mem_parser_test.cpp index 7a1e4b12..d8521d21 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_mem_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_mem_parser_test.cpp @@ -19,6 +19,7 @@ #include #include +#define private public #include "mem_parser/pbreader_mem_parser.h" #include "memory_plugin_result.pb.h" #include "memory_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_vmem_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_vmem_parser_test.cpp index bfd0c151..fad6cfa2 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_vmem_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_sys_vmem_parser_test.cpp @@ -19,6 +19,7 @@ #include #include +#define private public #include "mem_parser/pbreader_mem_parser.h" #include "memory_plugin_result.pb.h" #include "memory_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/pbreader_xpower_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/pbreader_xpower_parser_test.cpp index 3cac15a8..9de69dd2 100644 --- a/trace_streamer/test/unittest/pbreader_parser/pbreader_xpower_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/pbreader_xpower_parser_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "parser/common_types.h" #include "pbreader_xpower_parser.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/pbreader_parser/smaps_parser_test.cpp b/trace_streamer/test/unittest/pbreader_parser/smaps_parser_test.cpp index 564b6502..3685a79f 100644 --- a/trace_streamer/test/unittest/pbreader_parser/smaps_parser_test.cpp +++ b/trace_streamer/test/unittest/pbreader_parser/smaps_parser_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "mem_parser/pbreader_mem_parser.h" #include "memory_plugin_result.pb.h" #include "memory_plugin_result.pbreader.h" diff --git a/trace_streamer/test/unittest/ptreader_parser/event_parser_test.cpp b/trace_streamer/test/unittest/ptreader_parser/event_parser_test.cpp index 6201efd0..731b2b44 100644 --- a/trace_streamer/test/unittest/ptreader_parser/event_parser_test.cpp +++ b/trace_streamer/test/unittest/ptreader_parser/event_parser_test.cpp @@ -19,6 +19,7 @@ #include #include +#define private public #include "cpu_filter.h" #include "parser/ptreader_parser/bytrace_parser/bytrace_event_parser.h" #include "parser/ptreader_parser/ptreader_parser.h" @@ -39,6 +40,7 @@ public: void SetUp() { stream_.InitFilter(); + stream_.streamFilters_->configFilter_->switchConfig_.UpdateSyscallsTsSet("145;146;147"); } void TearDown() @@ -1174,5 +1176,105 @@ HWTEST_F(EventParserTest, HandlerCsfParseErrorFormate, TestSize.Level1) EXPECT_TRUE(result == PARSE_ERROR); } + +/** + * @tc.name: HandlerBParseSystemDataTracking + * @tc.desc: Parse "B|2483|H:hitraceTest|M62|key1=value1" using HandlerB interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerBParseSystemDataTracking, TestSize.Level1) +{ + TS_LOGI("test5-56"); + size_t length{4}; + TracePoint outPoint; + std::string str = "B|2483|H:hitraceTest"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerB(str, outPoint, length); + EXPECT_TRUE(result == PARSE_SUCCESS); + EXPECT_EQ(outPoint.customArgsId_, INVALID_UINT64); + + str = "B|2483|H:hitraceTest|M62|key1=value1"; + result = eventParser.printEventParser_.HandlerB(str, outPoint, length); + EXPECT_TRUE(result == PARSE_SUCCESS); + EXPECT_NE(outPoint.customArgsId_, INVALID_UINT64); +} + +/** + * @tc.name: HandlerCsfParseSystemDataTracking + * @tc.desc: Parse "S|2483|H:hitraceTest|M62|customCategoryTest|key1=value1" using HandlerCSF interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerCsfParseSystemDataTracking, TestSize.Level1) +{ + TS_LOGI("test5-57"); + size_t length{4}; + TracePoint outPoint; + outPoint.phase_ = 'S'; + std::string str = "S|2483|H:hitraceTest|123"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerCSF(str, outPoint, length); + EXPECT_TRUE(result == PARSE_SUCCESS); + EXPECT_EQ(outPoint.customCategoryId_, INVALID_UINT64); + + str = "S|2483|H:hitraceTest|123|M62|categoryTest|key=value"; + result = eventParser.printEventParser_.HandlerCSF(str, outPoint, length); + EXPECT_TRUE(result == PARSE_SUCCESS); + EXPECT_NE(outPoint.customCategoryId_, INVALID_UINT64); +} + +/** + * @tc.name: ParseSysEnterEventAndSysEnterEvent + * @tc.desc: Parse SysEnterEvent and SysEnterEvent interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSysEnterEventAndSysEnterEvent, TestSize.Level1) +{ + TS_LOGI("test5-58"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.eventName = "sys_enter"; + bytraceLine.argsStr = ""; + std::unordered_map args; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SysEnterEvent(args, bytraceLine); + EXPECT_TRUE(result); + result = eventParser.SysExitEvent(args, bytraceLine); + EXPECT_TRUE(result); + auto eventCount = stream_.traceDataCache_->GetConstSysCallData().Size(); + EXPECT_EQ(eventCount, 0); + + bytraceLine.argsStr = "NR"; + result = eventParser.SysEnterEvent(args, bytraceLine); + EXPECT_TRUE(result); + result = eventParser.SysExitEvent(args, bytraceLine); + EXPECT_TRUE(result); + eventCount = stream_.traceDataCache_->GetConstSysCallData().Size(); + EXPECT_EQ(eventCount, 0); + + bytraceLine.argsStr = "NR 146 (6, f663d4e8, 3, 42, 3, f663d4e8)"; + result = eventParser.SysEnterEvent(args, bytraceLine); + EXPECT_TRUE(result); + bytraceLine.argsStr = "NR 145 = 66"; + result = eventParser.SysExitEvent(args, bytraceLine); + EXPECT_TRUE(result); + EXPECT_EQ(eventCount, 0); + + bytraceLine.argsStr = "NR 146 = 66"; + result = eventParser.SysExitEvent(args, bytraceLine); + EXPECT_TRUE(result); + eventCount = stream_.traceDataCache_->GetConstSysCallData().Size(); + EXPECT_EQ(eventCount, 0); + + bytraceLine.argsStr = "NR 147 (6, f663d4e8, 3, 42, 3, f663d4e8)"; + result = eventParser.SysEnterEvent(args, bytraceLine); + EXPECT_TRUE(result); + + bytraceLine.argsStr = "NR 147 = 66"; + result = eventParser.SysExitEvent(args, bytraceLine); + EXPECT_TRUE(result); + eventCount = stream_.traceDataCache_->GetConstSysCallData().Size(); + EXPECT_EQ(eventCount, 1); +} } // namespace TraceStreamer } // namespace SysTuning diff --git a/trace_streamer/test/unittest/ptreader_parser/ptreader_parser_test.cpp b/trace_streamer/test/unittest/ptreader_parser/ptreader_parser_test.cpp index d7c37695..818a4b95 100644 --- a/trace_streamer/test/unittest/ptreader_parser/ptreader_parser_test.cpp +++ b/trace_streamer/test/unittest/ptreader_parser/ptreader_parser_test.cpp @@ -19,6 +19,7 @@ #include #include +#define private public #include "parser/ptreader_parser/ptreader_parser.h" #include "parser/common_types.h" #include "string_help.h" diff --git a/trace_streamer/test/unittest/query/query_file_test.cpp b/trace_streamer/test/unittest/query/query_file_test.cpp index 1e4d54db..0cf126a8 100644 --- a/trace_streamer/test/unittest/query/query_file_test.cpp +++ b/trace_streamer/test/unittest/query/query_file_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "file.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/query/query_metrics_test.cpp b/trace_streamer/test/unittest/query/query_metrics_test.cpp index 86243d4e..a2dce3a0 100644 --- a/trace_streamer/test/unittest/query/query_metrics_test.cpp +++ b/trace_streamer/test/unittest/query/query_metrics_test.cpp @@ -21,6 +21,7 @@ #include #include +#define private public #include "file.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/query/span_join_test.cpp b/trace_streamer/test/unittest/query/span_join_test.cpp index f339965d..4e7d6f26 100644 --- a/trace_streamer/test/unittest/query/span_join_test.cpp +++ b/trace_streamer/test/unittest/query/span_join_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "span_join.h" #include "trace_streamer_selector.h" diff --git a/trace_streamer/test/unittest/query/sqllite_prepar_cache_data_test.cpp b/trace_streamer/test/unittest/query/sqllite_prepar_cache_data_test.cpp index f4eb0394..df487147 100644 --- a/trace_streamer/test/unittest/query/sqllite_prepar_cache_data_test.cpp +++ b/trace_streamer/test/unittest/query/sqllite_prepar_cache_data_test.cpp @@ -18,6 +18,7 @@ #include #include +#define private public #include "export_test.h" #include "file.h" #include "sph_data.pb.h" diff --git a/trace_streamer/test/unittest/rawtrace/ftrace_field_processor_test.cpp b/trace_streamer/test/unittest/rawtrace/ftrace_field_processor_test.cpp index 4b429eda..841144bf 100644 --- a/trace_streamer/test/unittest/rawtrace/ftrace_field_processor_test.cpp +++ b/trace_streamer/test/unittest/rawtrace/ftrace_field_processor_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "ftrace_field_processor.h" #include "trace_streamer_selector.h" #include "securec.h" diff --git a/trace_streamer/test/unittest/rawtrace/rawtrace_cpu_detail_parse_test.cpp b/trace_streamer/test/unittest/rawtrace/rawtrace_cpu_detail_parse_test.cpp index df5e3f02..4555398e 100644 --- a/trace_streamer/test/unittest/rawtrace/rawtrace_cpu_detail_parse_test.cpp +++ b/trace_streamer/test/unittest/rawtrace/rawtrace_cpu_detail_parse_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "cpu_detail_parser.h" #include "ftrace_event_processor.h" #include "trace_streamer_selector.h" @@ -34,6 +35,11 @@ public: cpuDetailParser_ = std::make_unique(selector_.traceDataCache_.get(), selector_.streamFilters_.get()); ftraceEvent_ = std::make_unique(); + constexpr uint8_t PARAME_CNT_MAX = 10; + for (size_t i = 0; i < PARAME_CNT_MAX; i++) { + FieldFormat fieldFormat; + format_.fields.emplace_back(fieldFormat); + } } void TearDown() const {} diff --git a/trace_streamer/test/unittest/rawtrace/rawtrace_parser_test.cpp b/trace_streamer/test/unittest/rawtrace/rawtrace_parser_test.cpp index 57d22f76..fafc1ef5 100644 --- a/trace_streamer/test/unittest/rawtrace/rawtrace_parser_test.cpp +++ b/trace_streamer/test/unittest/rawtrace/rawtrace_parser_test.cpp @@ -20,6 +20,7 @@ #include #include +#define private public #include "export_test.h" #include "file.h" #include "rawtrace_parser.h" diff --git a/trace_streamer/test/unittest/table/table_test.cpp b/trace_streamer/test/unittest/table/table_test.cpp index 260e0bab..e799ff18 100644 --- a/trace_streamer/test/unittest/table/table_test.cpp +++ b/trace_streamer/test/unittest/table/table_test.cpp @@ -16,6 +16,7 @@ #include #include +#define private public #include "mem_parser/pbreader_mem_parser.h" #include "rpc_server.h" #include "trace_data_cache.h" @@ -1200,13 +1201,15 @@ HWTEST_F(TableTest, SyscallTableTest, TestSize.Level1) { TS_LOGI("test31-39"); std::string sqlSelect = "select * from syscall"; - int64_t sysCallNum = 1; - DataIndex type = stream_.traceDataCache_->GetDataIndex("type"); - uint64_t ipid = 1; - uint64_t timeStamp = 1663869124160; - int64_t ret = 1; - - stream_.traceDataCache_->GetSysCallData()->AppendSysCallData(sysCallNum, type, ipid, timeStamp, ret); + SyscallInfoRow syscallInfoRow; + syscallInfoRow.ts = 1663869124160; + syscallInfoRow.dur = 1; + syscallInfoRow.itid = 1; + syscallInfoRow.number = 1; + syscallInfoRow.args = stream_.traceDataCache_->GetDataIndex("(1,2,3)"); + syscallInfoRow.ret = 1; + + stream_.traceDataCache_->GetSysCallData()->AppendSysCallData(syscallInfoRow); EXPECT_EQ(stream_.traceDataCache_->SearchDatabase(sqlSelect, false), 1); } /** -- Gitee From 7c42c25f44d5a8a86719b73612d54bf45c1d6118 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 27 Jun 2025 14:41:54 +0800 Subject: [PATCH 40/51] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4=E5=A4=A7=E5=B0=8F?= =?UTF-8?q?=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- .../component/trace/sheet/TabPaneFilter.ts | 50 +++++++++---------- .../trace/sheet/parallel/TabPaneMtParallel.ts | 20 ++++---- .../sheet/parallel/TabPaneTimeParallel.ts | 14 +++--- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts index 5fdf7b28..a5f621e3 100644 --- a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts +++ b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts @@ -45,7 +45,7 @@ export class CpuStatus { cpu: number = 0; small: boolean = false; medium: boolean = false; - large: boolean = false; + big: boolean = false; } @element('tab-pane-filter') @@ -482,7 +482,7 @@ export class TabPaneFilter extends BaseElement { } //添加cpu列表 - setCoreConfigList(count: number, small: Array, mid: Array, large: Array): void { + setCoreConfigList(count: number, small: Array, mid: Array, big: Array): void { let divEl = this.shadowRoot!.querySelector('#data-core-popover > div > #tb_core_setting'); divEl!.innerHTML = ''; this.createCoreHeaderDiv(divEl); @@ -494,9 +494,9 @@ export class TabPaneFilter extends BaseElement { // @ts-ignore medium: mid.includes(i), // @ts-ignore - large: large.includes(i), + big: big.includes(i), }; - this.createCheckBoxLine(divEl, obj, small, mid, large); + this.createCheckBoxLine(divEl, obj, small, mid, big); } } @@ -519,14 +519,14 @@ export class TabPaneFilter extends BaseElement { mediumLine.textContent = 'M'; mediumLine.style.fontSize = '12px'; mediumLine.style.textAlign = 'center'; - let largeLine = document.createElement('div'); - largeLine.className = 'core_line'; - largeLine.style.fontWeight = 'bold'; - largeLine.textContent = 'L'; - largeLine.style.fontSize = '12px'; - largeLine.style.textAlign = 'center'; + let bigLine = document.createElement('div'); + bigLine.className = 'core_line'; + bigLine.style.fontWeight = 'bold'; + bigLine.textContent = 'B'; + bigLine.style.fontSize = '12px'; + bigLine.style.textAlign = 'center'; // @ts-ignore - tab?.append(...[cpuIdLine, smallLine, mediumLine, largeLine]); + tab?.append(...[cpuIdLine, smallLine, mediumLine, bigLine]); } //添加对应的cpu checkbox,并添加对应的监听事件 @@ -535,7 +535,7 @@ export class TabPaneFilter extends BaseElement { cpuStatus: CpuStatus, small: Array, mid: Array, - large: Array + big: Array ): void { let div = document.createElement('div'); div.textContent = cpuStatus.cpu + ''; @@ -553,43 +553,43 @@ export class TabPaneFilter extends BaseElement { midCheckBox.style.textAlign = 'center'; midCheckBox.style.marginLeft = 'auto'; midCheckBox.style.marginRight = 'auto'; - let largeCheckBox: LitCheckBox = new LitCheckBox(); - largeCheckBox.checked = cpuStatus.large; - largeCheckBox.setAttribute('not-close', ''); - largeCheckBox.style.marginLeft = 'auto'; - largeCheckBox.style.marginRight = 'auto'; + let bigCheckBox: LitCheckBox = new LitCheckBox(); + bigCheckBox.checked = cpuStatus.big; + bigCheckBox.setAttribute('not-close', ''); + bigCheckBox.style.marginLeft = 'auto'; + bigCheckBox.style.marginRight = 'auto'; smallCheckBox.addEventListener('change', (e: unknown) => { midCheckBox.checked = false; - largeCheckBox.checked = false; + bigCheckBox.checked = false; // @ts-ignore cpuStatus.small = e.detail.checked; // @ts-ignore this.canUpdateCheckList(e.detail.checked, small, cpuStatus.cpu); mid = mid.filter((it) => it !== cpuStatus.cpu); - large = large.filter((it) => it !== cpuStatus.cpu); + big = big.filter((it) => it !== cpuStatus.cpu); }); midCheckBox.addEventListener('change', (e: unknown) => { - largeCheckBox.checked = false; + bigCheckBox.checked = false; smallCheckBox.checked = false; // @ts-ignore cpuStatus.medium = e.detail.checked; // @ts-ignore this.canUpdateCheckList(e.detail.checked, mid, cpuStatus.cpu); - large = large.filter((it) => it !== cpuStatus.cpu); + big = big.filter((it) => it !== cpuStatus.cpu); small = small.filter((it) => it !== cpuStatus.cpu); }); - largeCheckBox.addEventListener('change', (e: unknown) => { + bigCheckBox.addEventListener('change', (e: unknown) => { midCheckBox.checked = false; smallCheckBox.checked = false; // @ts-ignore - cpuStatus.large = e.detail.checked; + cpuStatus.big = e.detail.checked; // @ts-ignore - this.canUpdateCheckList(e.detail.checked, large, cpuStatus.cpu); + this.canUpdateCheckList(e.detail.checked, big, cpuStatus.cpu); mid = mid.filter((it) => it !== cpuStatus.cpu); small = small.filter((it) => it !== cpuStatus.cpu); }); // @ts-ignore - divEl!.append(...[div, smallCheckBox, midCheckBox, largeCheckBox]); + divEl!.append(...[div, smallCheckBox, midCheckBox, bigCheckBox]); } //判断checkList数组是否需要push数据或删除数据 diff --git a/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts b/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts index 0da3c2f3..b888b2f5 100644 --- a/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts +++ b/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts @@ -32,7 +32,7 @@ const NUM_DIGITS: number = 3; const CORE_NUM: number = 12; const SMALL_CPU_NUM: Array = [0, 1, 2, 3]; const MID_CPU_NUM12: Array = [4, 5, 6, 7, 8, 9]; -const LARGE_CPU_NUM12: Array = [10, 11]; +const BIG_CPU_NUM12: Array = [10, 11]; const CORE_JSON = { 'group1': [4, 5], 'group2': [6, 7], @@ -43,7 +43,7 @@ export class CpuStatus { cpu: number = 0; small: boolean = false; medium: boolean = false; - large: boolean = false; + big: boolean = false; } @element('tabpane-mt-parallel') export class TabPaneMtParallel extends BaseElement { @@ -57,7 +57,7 @@ export class TabPaneMtParallel extends BaseElement { private leftStartNs: number = 0; private rightEndNs: number = 0; private midCores: Array = []; - private largeCores: Array = []; + private bigCores: Array = []; private smallCores: Array = []; private isCreateCpu: boolean = true; private isCreateGroup: boolean = true; @@ -94,7 +94,7 @@ export class TabPaneMtParallel extends BaseElement { if (this.isCreateCpu) { this.initDefaultConfig(); this.isCreateCpu = false; - this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.largeCores); + this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.bigCores); }; }; this.litSettingPopoverEl!.querySelector('.confirm-button')!.addEventListener('click', (e: unknown) => { @@ -171,7 +171,7 @@ export class TabPaneMtParallel extends BaseElement { updateDataSource(flag: boolean): void { let param = flag ? this.bufferGroupMap.size !== 0 : Utils.getInstance().getWinCpuCount() === CORE_NUM; let value = flag ? this.bufferGroupMap : new Map(Object.entries(CORE_JSON)); - if ((this.midCores.length || this.largeCores.length || this.smallCores.length) && param) { + if ((this.midCores.length || this.bigCores.length || this.smallCores.length) && param) { this.coreTypeMap.clear(); this.dataSourceMap.clear(); this.parallelTable!.loading = true; @@ -186,7 +186,7 @@ export class TabPaneMtParallel extends BaseElement { } } async getMtParallelData(obj: Map) :Promise { - let cpuObj: unknown = { 'L': this.largeCores, 'M': this.midCores, 'S': this.smallCores }; + let cpuObj: unknown = { 'B': this.bigCores, 'M': this.midCores, 'S': this.smallCores }; let processIds: Array = [...new Set(this.selectionParam!.processIds)]; for (const [key, cpuGroup] of obj.entries()) { //判断配的的组是否在同一个核分类中,如果在,返回是那个核分类,反之,返回null @@ -238,7 +238,7 @@ export class TabPaneMtParallel extends BaseElement { } //判断自配的相同物理核是否符合计算MT并行度的要求 - handleSamePhysicsCore(arr: unknown, obj: { 'L': Array; 'M': Array; 'S': Array }): string | null { + handleSamePhysicsCore(arr: unknown, obj: { 'B': Array; 'M': Array; 'S': Array }): string | null { let core = null; // @ts-ignore if (arr.length > 2) { return null } @@ -386,11 +386,11 @@ export class TabPaneMtParallel extends BaseElement { if (Utils.getInstance().getWinCpuCount() === CORE_NUM) { this.smallCores = [...SMALL_CPU_NUM]; this.midCores = [...MID_CPU_NUM12]; - this.largeCores = [...LARGE_CPU_NUM12]; + this.bigCores = [...BIG_CPU_NUM12]; } else { this.smallCores = []; this.midCores = []; - this.largeCores = []; + this.bigCores = []; } } } @@ -424,7 +424,7 @@ export class TabPaneMtParallel extends BaseElement { disabled: Utils.getInstance().getWinCpuCount() === CORE_NUM && str !== 'cut' && this.isReset ? !(switchArr.includes(i)) : - !([...this.smallCores, ...this.midCores, ...this.largeCores].includes(i)) + !([...this.smallCores, ...this.midCores, ...this.bigCores].includes(i)) }; this.creatGroupLineDIv(obj); } diff --git a/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts b/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts index 4e0acbdd..d8de4d19 100644 --- a/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts +++ b/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts @@ -31,7 +31,7 @@ const NUM_DIGITS: number = 3; const CORE_NUM: number = 12; const SMALL_CPU_NUM: Array = [0, 1, 2, 3]; const MID_CPU_NUM12: Array = [4, 5, 6, 7, 8, 9]; -const LARGE_CPU_NUM12: Array = [10, 11]; +const BIG_CPU_NUM12: Array = [10, 11]; @element('tabpane-time-parallel') export class TabPaneTimeParallel extends BaseElement { @@ -44,7 +44,7 @@ export class TabPaneTimeParallel extends BaseElement { private leftStartNs: number = 0; private rightEndNs: number = 0; private midCores: Array = []; - private largeCores: Array = []; + private bigCores: Array = []; private smallCores: Array = []; private initStatus: boolean = true; @@ -70,7 +70,7 @@ export class TabPaneTimeParallel extends BaseElement { if (this.initStatus) { this.initDefaultConfig(); this.initStatus = false; - this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.largeCores); + this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.bigCores); } }; this.litPopoverEl!.querySelector('.confirm-button')!.addEventListener('click', (e: unknown) => { @@ -85,7 +85,7 @@ export class TabPaneTimeParallel extends BaseElement { // @ts-ignore this.litPopoverEl!.visible = false; //当大中小核未分组时,默认查询所有核 - if (!this.midCores.length && !this.largeCores.length && !this.smallCores.length) { + if (!this.midCores.length && !this.bigCores.length && !this.smallCores.length) { this.assignAllCore(); } else { this.assignGroupCore(); @@ -144,11 +144,11 @@ export class TabPaneTimeParallel extends BaseElement { if (Utils.getInstance().getWinCpuCount() === CORE_NUM) { this.smallCores = [...SMALL_CPU_NUM]; this.midCores = [...MID_CPU_NUM12]; - this.largeCores = [...LARGE_CPU_NUM12]; + this.bigCores = [...BIG_CPU_NUM12]; } else { this.smallCores = []; this.midCores = []; - this.largeCores = []; + this.bigCores = []; } } } @@ -166,7 +166,7 @@ export class TabPaneTimeParallel extends BaseElement { let dataSourceMap: Map = new Map(); let processIds: Array = [...new Set(this.selectionParam!.processIds)]; let cpuObj: Object = { - 'L': this.largeCores, + 'B': this.bigCores, 'M': this.midCores, 'S': this.smallCores }; -- Gitee From e21f91ce76bf57a610b5ef99b6c70db299c84d31 Mon Sep 17 00:00:00 2001 From: zhangzepeng Date: Tue, 1 Jul 2025 16:04:02 +0800 Subject: [PATCH 41/51] =?UTF-8?q?ai=E6=8E=A5=E5=8F=A3=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzepeng --- ide/server/main.go | 10 ++++++++++ ide/src/base-ui/menu/LitMainMenu.ts | 2 +- ide/src/trace/SpApplication.ts | 13 +++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ide/server/main.go b/ide/server/main.go index 772b1c4a..ab310beb 100644 --- a/ide/server/main.go +++ b/ide/server/main.go @@ -53,6 +53,7 @@ const HttpPort = 9000 var exPath string var serveInfo string +var aiInfo string var msgPublishData MsgPublishData var hdcPublicKey string var hdcPrivateKey *rsa.PrivateKey @@ -177,6 +178,7 @@ func main() { mux.Handle("/application/upload/", http.StripPrefix("/application/upload/", http.FileServer(http.Dir(filepath.FromSlash(exPath+"/upload"))))) mux.HandleFunc("/application/download-file", downloadHandler) mux.HandleFunc("/application/serverInfo", serverInfo) + mux.HandleFunc("/application/getAiInfo", getAiInfo) mux.HandleFunc("/application/hdcPublicKey", getHdcPublicKey) mux.HandleFunc("/application/encryptHdcMsg", encryptHdcMsg) mux.HandleFunc("/application/signatureHdcMsg", signatureHdcMsg) @@ -257,6 +259,12 @@ func serverInfo(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) } +func getAiInfo(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("ai_info", aiInfo) + w.WriteHeader(200) +} + func getHdcPublicKey(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "text/json") @@ -340,6 +348,7 @@ func getMsgPublish(w http.ResponseWriter, r *http.Request) { type ServerConfig struct { ServeInfo string `json:"ServeInfo"` MsgPublishFile string `json:"MsgPublishFile"` + AiInfo string } type MsgPublishData struct { @@ -371,6 +380,7 @@ func readReqServerConfig() { return } serveInfo = sc.ServeInfo + aiInfo = sc.AiInfo msgPublishData.Mux.Lock() msgPublishData.FilePath = sc.MsgPublishFile msgPublishData.Mux.Unlock() diff --git a/ide/src/base-ui/menu/LitMainMenu.ts b/ide/src/base-ui/menu/LitMainMenu.ts index ab22f2d6..433937a1 100644 --- a/ide/src/base-ui/menu/LitMainMenu.ts +++ b/ide/src/base-ui/menu/LitMainMenu.ts @@ -299,7 +299,7 @@ export class LitMainMenu extends BaseElement {
- +
diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index bae7d464..e5d82322 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -291,6 +291,19 @@ export class SpApplication extends BaseElement { SpStatisticsHttpUtil.addUserVisitAction('visit'); } }) + let aiurl = `${window.location.protocol}//${window.location.host.split(':')[0]}:${window.location.port + }${window.location.pathname}getAiInfo`; + fetch(aiurl, { method: 'GET' }).then((res) => { + if (res.headers) { + const headers = res.headers; + let aiAnalysisShow = this.shadowRoot + ?.querySelector('lit-main-menu')! + .shadowRoot!.querySelector('.ai_analysis') as HTMLDivElement; + if (headers.get('ai_info') !== '') { + aiAnalysisShow.style.display = ''; + } + } + }) LongTraceDBUtils.getInstance().createDBAndTable().then(); } -- Gitee From 7a4c1a063a099741c96dcdae116da8a3af076ad0 Mon Sep 17 00:00:00 2001 From: wangziyi Date: Wed, 2 Jul 2025 10:00:07 +0800 Subject: [PATCH 42/51] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4clocks=E4=B8=8Bheca?= =?UTF-8?q?=5Ffreq=E6=B3=B3=E9=81=93=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangziyi --- ide/src/trace/component/chart/SpClockChart.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ide/src/trace/component/chart/SpClockChart.ts b/ide/src/trace/component/chart/SpClockChart.ts index a521cb0a..9fae8194 100644 --- a/ide/src/trace/component/chart/SpClockChart.ts +++ b/ide/src/trace/component/chart/SpClockChart.ts @@ -47,8 +47,14 @@ export class SpClockChart { } else { this.trace.rowsEL?.appendChild(folder); } - await this.initData(folder, clockList, traceId); + // heca_freq Frequency移动到数组末尾 + const index = clockList.findIndex(item => item.name === 'heca_freq Frequency'); + if (index !== -1) { + const [item] = clockList.splice(index, 1); + clockList.push(item); + } await this.initDmaFence(folder); + await this.initData(folder, clockList, traceId); } private clockSupplierFrame( -- Gitee From 38c9a0b88703eecb5641a52e8a84e08b6a6a4ac2 Mon Sep 17 00:00:00 2001 From: wangziyi Date: Wed, 2 Jul 2025 10:45:21 +0800 Subject: [PATCH 43/51] =?UTF-8?q?=E8=B0=83=E6=95=B4clocks=E6=8E=92?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangziyi --- ide/src/trace/component/chart/SpClockChart.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ide/src/trace/component/chart/SpClockChart.ts b/ide/src/trace/component/chart/SpClockChart.ts index 9fae8194..707ac3b0 100644 --- a/ide/src/trace/component/chart/SpClockChart.ts +++ b/ide/src/trace/component/chart/SpClockChart.ts @@ -50,8 +50,10 @@ export class SpClockChart { // heca_freq Frequency移动到数组末尾 const index = clockList.findIndex(item => item.name === 'heca_freq Frequency'); if (index !== -1) { - const [item] = clockList.splice(index, 1); - clockList.push(item); + const item = clockList.splice(index, 1); + if (item && item.length) { + clockList.push(item[0]); + } } await this.initDmaFence(folder); await this.initData(folder, clockList, traceId); -- Gitee From 05529b20ba419c094dfd66a1e08705d3ae87faf1 Mon Sep 17 00:00:00 2001 From: wangyujie Date: Fri, 4 Jul 2025 11:00:40 +0800 Subject: [PATCH 44/51] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4=E5=A4=A7=E5=B0=8F?= =?UTF-8?q?=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangyujie --- .../doc/quickstart_schedulinganalysis.html | 4 +- .../Schedulinganalysis/CPUdetailsetting.jpg | Bin 97100 -> 121620 bytes .../figures/Schedulinganalysis/CPUsetting.jpg | Bin 30579 -> 27650 bytes .../schedulingAnalysis/CheckCpuSetting.ts | 32 +++++------ .../Top20ThreadCpuUsage.html.ts | 8 +-- .../schedulingAnalysis/Top20ThreadCpuUsage.ts | 54 +++++++++--------- .../component/trace/sheet/TabPaneFilter.ts | 52 ++++++++--------- .../trace/sheet/parallel/TabPaneMtParallel.ts | 18 +++--- .../sheet/parallel/TabPaneTimeParallel.ts | 14 ++--- .../ProcedureLogicWorkerSchedulingAnalysis.ts | 38 ++++++------ 10 files changed, 110 insertions(+), 110 deletions(-) diff --git a/ide/src/doc/quickstart_schedulinganalysis.html b/ide/src/doc/quickstart_schedulinganalysis.html index a4104ab2..e7738ee1 100644 --- a/ide/src/doc/quickstart_schedulinganalysis.html +++ b/ide/src/doc/quickstart_schedulinganalysis.html @@ -1016,7 +1016,7 @@ duration:运行总时长。

Top20线程大中小核占用率

- 选择Thread Analysis标签页,各个CPU通过勾选big或者middle或者small来设置CPU的分类。 + 选择Thread Analysis标签页,各个CPU通过勾选big或者middle或者little来设置CPU的分类。
GitHub Logo
@@ -1080,7 +1080,7 @@ middle core:中核占用时长。

  • -small core:小核占用时长。
    +little core:小核占用时长。
     
  • diff --git a/ide/src/figures/Schedulinganalysis/CPUdetailsetting.jpg b/ide/src/figures/Schedulinganalysis/CPUdetailsetting.jpg index 9683b732eee0a99ca2afd50a42bae44befba67cb..b414073a0879f54e8bfc0bbf4822842950c40e9c 100644 GIT binary patch literal 121620 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

    pMcIZUZcL4@WOQiy3)8PggRMHEV#DHd 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 diff --git a/ide/src/figures/Schedulinganalysis/CPUsetting.jpg b/ide/src/figures/Schedulinganalysis/CPUsetting.jpg index b2d43b9b41cfd5023acfd195cbaf829355ba9f7d..f46651947d5996a0fdeeb97870742ef18497ee74 100644 GIT binary patch literal 27650 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 { midCheckBox.checked = false; - smallCheckBox.checked = false; + littleCheckBox.checked = false; cpuSetting.big = true; CheckCpuSetting.big_cores.push(cpuSetting.cpu); CheckCpuSetting.mid_cores = CheckCpuSetting.mid_cores.filter((it): boolean => it !== cpuSetting.cpu); - CheckCpuSetting.small_cores = CheckCpuSetting.small_cores.filter((it): boolean => it !== cpuSetting.cpu); + CheckCpuSetting.little_cores = CheckCpuSetting.little_cores.filter((it): boolean => it !== cpuSetting.cpu); }); midCheckBox.addEventListener('change', (): void => { bigCheckBox.checked = false; - smallCheckBox.checked = false; + littleCheckBox.checked = false; cpuSetting.middle = true; CheckCpuSetting.mid_cores.push(cpuSetting.cpu); CheckCpuSetting.big_cores = CheckCpuSetting.big_cores.filter((it): boolean => it !== cpuSetting.cpu); - CheckCpuSetting.small_cores = CheckCpuSetting.small_cores.filter((it): boolean => it !== cpuSetting.cpu); + CheckCpuSetting.little_cores = CheckCpuSetting.little_cores.filter((it): boolean => it !== cpuSetting.cpu); }); - smallCheckBox.addEventListener('change', (): void => { + littleCheckBox.addEventListener('change', (): void => { midCheckBox.checked = false; bigCheckBox.checked = false; - cpuSetting.small = true; - CheckCpuSetting.small_cores.push(cpuSetting.cpu); + cpuSetting.little = true; + CheckCpuSetting.little_cores.push(cpuSetting.cpu); CheckCpuSetting.mid_cores = CheckCpuSetting.mid_cores.filter((it): boolean => it !== cpuSetting.cpu); CheckCpuSetting.big_cores = CheckCpuSetting.big_cores.filter((it): boolean => it !== cpuSetting.cpu); }); - this.table?.append(...[div, bigCheckBox, midCheckBox, smallCheckBox]); + this.table?.append(...[div, bigCheckBox, midCheckBox, littleCheckBox]); } createHeaderDiv(): void { @@ -139,14 +139,14 @@ export class CheckCpuSetting extends BaseElement { let column4 = document.createElement('div'); column4.className = 'setting_line'; column4.style.fontWeight = 'bold'; - column4.textContent = 'small'; + column4.textContent = 'little'; this.table?.append(...[column1, column2, column3, column4]); } static resetCpuSettings(): void { CheckCpuSetting.init_setting = false; CheckCpuSetting.big_cores = []; - CheckCpuSetting.small_cores = []; + CheckCpuSetting.little_cores = []; CheckCpuSetting.mid_cores = []; } diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.html.ts b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.html.ts index 34f7f3ac..5f543de0 100644 --- a/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.html.ts +++ b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.html.ts @@ -80,23 +80,23 @@ export const Top20ThreadCpuUsageHtml = `

    big
    mid
    -
    small
    +
    little
    -
    +
    Top20线程小核占用率
    -
    small
    +
    little
    - +
    diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts index e1c86a49..c78526ff 100644 --- a/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts +++ b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts @@ -36,7 +36,7 @@ export class Top20ThreadCpuUsage extends BaseElement { private table: LitTable | null | undefined; private tableBig: LitTable | null | undefined; private tableMid: LitTable | null | undefined; - private tableSmall: LitTable | null | undefined; + private tableLittle: LitTable | null | undefined; private chartTotal: LitChartColumn | null | undefined; private chart2: LitChartColumn | null | undefined; private chart3: LitChartColumn | null | undefined; @@ -49,10 +49,10 @@ export class Top20ThreadCpuUsage extends BaseElement { private data: Array = []; private dataBig: Array = []; private dataMid: Array = []; - private dataSmall: Array = []; + private dataLittle: Array = []; private sort: unknown = { total: { key: '', sort: 0 }, - small: { key: '', sort: 0 }, + little: { key: '', sort: 0 }, mid: { key: '', sort: 0 }, big: { key: '', sort: 0 }, }; @@ -82,9 +82,9 @@ export class Top20ThreadCpuUsage extends BaseElement { `; - private smallColumn = ` - - + private littleColumn = ` + + `; initElements(): void { @@ -93,14 +93,14 @@ export class Top20ThreadCpuUsage extends BaseElement { this.table = this.shadowRoot!.querySelector('#tb-thread-usage'); this.tableBig = this.shadowRoot!.querySelector('#tb-thread-big'); this.tableMid = this.shadowRoot!.querySelector('#tb-thread-mid'); - this.tableSmall = this.shadowRoot!.querySelector('#tb-thread-small'); + this.tableLittle = this.shadowRoot!.querySelector('#tb-thread-little'); this.chartTotal = this.shadowRoot!.querySelector('#chart_total'); this.chart2 = this.shadowRoot!.querySelector('#chart_2'); this.chart3 = this.shadowRoot!.querySelector('#chart_3'); this.chart4 = this.shadowRoot!.querySelector('#chart_4'); this.map = new Map(); this.map.set('total', { chart: this.chartTotal!, table: this.table! }); - this.map.set('small', { chart: this.chart2!, table: this.tableSmall! }); + this.map.set('little', { chart: this.chart2!, table: this.tableLittle! }); this.map.set('mid', { chart: this.chart3!, table: this.tableMid! }); this.map.set('big', { chart: this.chart4!, table: this.tableBig! }); this.setting = this.shadowRoot!.querySelector('#setting'); @@ -110,8 +110,8 @@ export class Top20ThreadCpuUsage extends BaseElement { //@ts-ignore (this.shadowRoot!.querySelector('#total')! as unknown).style.display = 'grid'; //@ts-ignore - (this.shadowRoot!.querySelector('#small')! as unknown).style.display = - CheckCpuSetting.small_cores.length > 0 ? 'grid' : 'none'; + (this.shadowRoot!.querySelector('#little')! as unknown).style.display = + CheckCpuSetting.little_cores.length > 0 ? 'grid' : 'none'; //@ts-ignore (this.shadowRoot!.querySelector('#mid')! as unknown).style.display = CheckCpuSetting.mid_cores.length > 0 ? 'grid' : 'none'; @@ -153,9 +153,9 @@ export class Top20ThreadCpuUsage extends BaseElement { if (key === 'total') { //@ts-ignore this.sortByColumn(evt.detail, tab, this.data); - } else if (key === 'small') { + } else if (key === 'little') { //@ts-ignore - this.sortByColumn(evt.detail, tab, this.dataSmall); + this.sortByColumn(evt.detail, tab, this.dataLittle); } else if (key === 'mid') { //@ts-ignore this.sortByColumn(evt.detail, tab, this.dataMid); @@ -211,8 +211,8 @@ export class Top20ThreadCpuUsage extends BaseElement { key = 'big'; } else if (key === 'midTimeStr') { key = 'mid'; - } else if (key === 'smallTimeStr') { - key = 'small'; + } else if (key === 'littleTimeStr') { + key = 'little'; } else if ( key === 'bigPercent' || key === 'ratio' || @@ -296,7 +296,7 @@ export class Top20ThreadCpuUsage extends BaseElement { //@ts-ignore mid: it.mid, //@ts-ignore - small: it.small, + little: it.little, no: index + 1, visible: 1, //@ts-ignore @@ -304,13 +304,13 @@ export class Top20ThreadCpuUsage extends BaseElement { //@ts-ignore midPercent: it.midPercent, //@ts-ignore - smallPercent: it.smallPercent, + littlePercent: it.littlePercent, //@ts-ignore bigTimeStr: it.bigTimeStr, //@ts-ignore midTimeStr: it.midTimeStr, //@ts-ignore - smallTimeStr: it.smallTimeStr, + littleTimeStr: it.littleTimeStr, hideHandler: (): void => { //@ts-ignore let arr = source.filter((o) => o.visible === 1); @@ -333,8 +333,8 @@ export class Top20ThreadCpuUsage extends BaseElement { private assignmentData(key: string, source: unknown[], obj: { chart: LitChartColumn; table: LitTable }): void { if (key === 'total') { this.data = source; - } else if (key === 'small') { - this.dataSmall = source; + } else if (key === 'little') { + this.dataLittle = source; } else if (key === 'mid') { this.dataMid = source; } else if (key === 'big') { @@ -362,7 +362,7 @@ export class Top20ThreadCpuUsage extends BaseElement { return '#2f72f8'; //@ts-ignore } else if (a.size === 'middle core') { return '#ffab67'; //@ts-ignore - } else if (a.size === 'small core') { + } else if (a.size === 'little core') { return '#a285d2'; } else { return '#0a59f7'; @@ -450,10 +450,10 @@ export class Top20ThreadCpuUsage extends BaseElement { pName: obj.pName, //@ts-ignore tid: obj.tid, //@ts-ignore tName: obj.tName, //@ts-ignore - total: obj.small, - size: 'small core', //@ts-ignore + total: obj.little, + size: 'little core', //@ts-ignore no: obj.no, //@ts-ignore - timeStr: obj.smallTimeStr, + timeStr: obj.littleTimeStr, }); } else { data.push({ @@ -479,7 +479,7 @@ export class Top20ThreadCpuUsage extends BaseElement { { bigCores: CheckCpuSetting.big_cores, midCores: CheckCpuSetting.mid_cores, - smallCores: CheckCpuSetting.small_cores, + littleCores: CheckCpuSetting.little_cores, }, undefined, handler @@ -490,13 +490,13 @@ export class Top20ThreadCpuUsage extends BaseElement { getTableColumns(type: string): string { if (type === 'total') { - return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.smallColumn}`; + return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.littleColumn}`; } else if (type === 'big') { return `${this.publicColumns}${this.bigColumn}`; } else if (type === 'mid') { return `${this.publicColumns}${this.midColumn}`; - } else if (type === 'small') { - return `${this.publicColumns}${this.smallColumn}`; + } else if (type === 'little') { + return `${this.publicColumns}${this.littleColumn}`; } else { return ''; } diff --git a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts index a5f621e3..fbaaf9f1 100644 --- a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts +++ b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts @@ -43,7 +43,7 @@ export interface MiningData { export class CpuStatus { cpu: number = 0; - small: boolean = false; + little: boolean = false; medium: boolean = false; big: boolean = false; } @@ -482,7 +482,7 @@ export class TabPaneFilter extends BaseElement { } //添加cpu列表 - setCoreConfigList(count: number, small: Array, mid: Array, big: Array): void { + setCoreConfigList(count: number, little: Array, mid: Array, big: Array): void { let divEl = this.shadowRoot!.querySelector('#data-core-popover > div > #tb_core_setting'); divEl!.innerHTML = ''; this.createCoreHeaderDiv(divEl); @@ -490,13 +490,13 @@ export class TabPaneFilter extends BaseElement { let obj = { cpu: i, // @ts-ignore - small: small.includes(i), + little: little.includes(i), // @ts-ignore medium: mid.includes(i), // @ts-ignore big: big.includes(i), }; - this.createCheckBoxLine(divEl, obj, small, mid, big); + this.createCheckBoxLine(divEl, obj, little, mid, big); } } @@ -507,12 +507,12 @@ export class TabPaneFilter extends BaseElement { cpuIdLine.style.fontSize = '12px'; cpuIdLine.textContent = 'Cpu'; cpuIdLine.style.textAlign = 'center'; - let smallLine = document.createElement('div'); - smallLine.className = 'core_line'; - smallLine.style.fontWeight = 'bold'; - smallLine.textContent = 'S'; - smallLine.style.fontSize = '12px'; - smallLine.style.textAlign = 'center'; + let littleLine = document.createElement('div'); + littleLine.className = 'core_line'; + littleLine.style.fontWeight = 'bold'; + littleLine.textContent = 'L'; + littleLine.style.fontSize = '12px'; + littleLine.style.textAlign = 'center'; let mediumLine = document.createElement('div'); mediumLine.className = 'core_line'; mediumLine.style.fontWeight = 'bold'; @@ -526,14 +526,14 @@ export class TabPaneFilter extends BaseElement { bigLine.style.fontSize = '12px'; bigLine.style.textAlign = 'center'; // @ts-ignore - tab?.append(...[cpuIdLine, smallLine, mediumLine, bigLine]); + tab?.append(...[cpuIdLine, littleLine, mediumLine, bigLine]); } //添加对应的cpu checkbox,并添加对应的监听事件 createCheckBoxLine( divEl: unknown, cpuStatus: CpuStatus, - small: Array, + little: Array, mid: Array, big: Array ): void { @@ -541,12 +541,12 @@ export class TabPaneFilter extends BaseElement { div.textContent = cpuStatus.cpu + ''; div.style.textAlign = 'center'; div.style.fontWeight = 'normal'; - let smallCheckBox: LitCheckBox = new LitCheckBox(); - smallCheckBox.checked = cpuStatus.small; - smallCheckBox.setAttribute('not-close', ''); - smallCheckBox.style.textAlign = 'center'; - smallCheckBox.style.marginLeft = 'auto'; - smallCheckBox.style.marginRight = 'auto'; + let littleCheckBox: LitCheckBox = new LitCheckBox(); + littleCheckBox.checked = cpuStatus.little; + littleCheckBox.setAttribute('not-close', ''); + littleCheckBox.style.textAlign = 'center'; + littleCheckBox.style.marginLeft = 'auto'; + littleCheckBox.style.marginRight = 'auto'; let midCheckBox: LitCheckBox = new LitCheckBox(); midCheckBox.checked = cpuStatus.medium; midCheckBox.setAttribute('not-close', ''); @@ -558,38 +558,38 @@ export class TabPaneFilter extends BaseElement { bigCheckBox.setAttribute('not-close', ''); bigCheckBox.style.marginLeft = 'auto'; bigCheckBox.style.marginRight = 'auto'; - smallCheckBox.addEventListener('change', (e: unknown) => { + littleCheckBox.addEventListener('change', (e: unknown) => { midCheckBox.checked = false; bigCheckBox.checked = false; // @ts-ignore - cpuStatus.small = e.detail.checked; + cpuStatus.little = e.detail.checked; // @ts-ignore - this.canUpdateCheckList(e.detail.checked, small, cpuStatus.cpu); + this.canUpdateCheckList(e.detail.checked, little, cpuStatus.cpu); mid = mid.filter((it) => it !== cpuStatus.cpu); big = big.filter((it) => it !== cpuStatus.cpu); }); midCheckBox.addEventListener('change', (e: unknown) => { bigCheckBox.checked = false; - smallCheckBox.checked = false; + littleCheckBox.checked = false; // @ts-ignore cpuStatus.medium = e.detail.checked; // @ts-ignore this.canUpdateCheckList(e.detail.checked, mid, cpuStatus.cpu); big = big.filter((it) => it !== cpuStatus.cpu); - small = small.filter((it) => it !== cpuStatus.cpu); + little = little.filter((it) => it !== cpuStatus.cpu); }); bigCheckBox.addEventListener('change', (e: unknown) => { midCheckBox.checked = false; - smallCheckBox.checked = false; + littleCheckBox.checked = false; // @ts-ignore cpuStatus.big = e.detail.checked; // @ts-ignore this.canUpdateCheckList(e.detail.checked, big, cpuStatus.cpu); mid = mid.filter((it) => it !== cpuStatus.cpu); - small = small.filter((it) => it !== cpuStatus.cpu); + little = little.filter((it) => it !== cpuStatus.cpu); }); // @ts-ignore - divEl!.append(...[div, smallCheckBox, midCheckBox, bigCheckBox]); + divEl!.append(...[div, littleCheckBox, midCheckBox, bigCheckBox]); } //判断checkList数组是否需要push数据或删除数据 diff --git a/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts b/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts index b888b2f5..123880cc 100644 --- a/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts +++ b/ide/src/trace/component/trace/sheet/parallel/TabPaneMtParallel.ts @@ -30,7 +30,7 @@ import { Utils } from '../../base/Utils'; const UNIT: number = 1000000.0; const NUM_DIGITS: number = 3; const CORE_NUM: number = 12; -const SMALL_CPU_NUM: Array = [0, 1, 2, 3]; +const LITTLE_CPU_NUM: Array = [0, 1, 2, 3]; const MID_CPU_NUM12: Array = [4, 5, 6, 7, 8, 9]; const BIG_CPU_NUM12: Array = [10, 11]; const CORE_JSON = { @@ -41,7 +41,7 @@ const CORE_JSON = { }; export class CpuStatus { cpu: number = 0; - small: boolean = false; + little: boolean = false; medium: boolean = false; big: boolean = false; } @@ -58,7 +58,7 @@ export class TabPaneMtParallel extends BaseElement { private rightEndNs: number = 0; private midCores: Array = []; private bigCores: Array = []; - private smallCores: Array = []; + private littleCores: Array = []; private isCreateCpu: boolean = true; private isCreateGroup: boolean = true; private coreTypeMap: Map = new Map(); @@ -94,7 +94,7 @@ export class TabPaneMtParallel extends BaseElement { if (this.isCreateCpu) { this.initDefaultConfig(); this.isCreateCpu = false; - this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.bigCores); + this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.littleCores, this.midCores, this.bigCores); }; }; this.litSettingPopoverEl!.querySelector('.confirm-button')!.addEventListener('click', (e: unknown) => { @@ -171,7 +171,7 @@ export class TabPaneMtParallel extends BaseElement { updateDataSource(flag: boolean): void { let param = flag ? this.bufferGroupMap.size !== 0 : Utils.getInstance().getWinCpuCount() === CORE_NUM; let value = flag ? this.bufferGroupMap : new Map(Object.entries(CORE_JSON)); - if ((this.midCores.length || this.bigCores.length || this.smallCores.length) && param) { + if ((this.midCores.length || this.bigCores.length || this.littleCores.length) && param) { this.coreTypeMap.clear(); this.dataSourceMap.clear(); this.parallelTable!.loading = true; @@ -186,7 +186,7 @@ export class TabPaneMtParallel extends BaseElement { } } async getMtParallelData(obj: Map) :Promise { - let cpuObj: unknown = { 'B': this.bigCores, 'M': this.midCores, 'S': this.smallCores }; + let cpuObj: unknown = { 'B': this.bigCores, 'M': this.midCores, 'L': this.littleCores }; let processIds: Array = [...new Set(this.selectionParam!.processIds)]; for (const [key, cpuGroup] of obj.entries()) { //判断配的的组是否在同一个核分类中,如果在,返回是那个核分类,反之,返回null @@ -384,11 +384,11 @@ export class TabPaneMtParallel extends BaseElement { initDefaultConfig(): void { if (this.isCreateCpu) { if (Utils.getInstance().getWinCpuCount() === CORE_NUM) { - this.smallCores = [...SMALL_CPU_NUM]; + this.littleCores = [...LITTLE_CPU_NUM]; this.midCores = [...MID_CPU_NUM12]; this.bigCores = [...BIG_CPU_NUM12]; } else { - this.smallCores = []; + this.littleCores = []; this.midCores = []; this.bigCores = []; } @@ -424,7 +424,7 @@ export class TabPaneMtParallel extends BaseElement { disabled: Utils.getInstance().getWinCpuCount() === CORE_NUM && str !== 'cut' && this.isReset ? !(switchArr.includes(i)) : - !([...this.smallCores, ...this.midCores, ...this.bigCores].includes(i)) + !([...this.littleCores, ...this.midCores, ...this.bigCores].includes(i)) }; this.creatGroupLineDIv(obj); } diff --git a/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts b/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts index d8de4d19..34535d25 100644 --- a/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts +++ b/ide/src/trace/component/trace/sheet/parallel/TabPaneTimeParallel.ts @@ -29,7 +29,7 @@ import { Utils } from '../../base/Utils'; const UNIT: number = 1000000.0; const NUM_DIGITS: number = 3; const CORE_NUM: number = 12; -const SMALL_CPU_NUM: Array = [0, 1, 2, 3]; +const LITTLE_CPU_NUM: Array = [0, 1, 2, 3]; const MID_CPU_NUM12: Array = [4, 5, 6, 7, 8, 9]; const BIG_CPU_NUM12: Array = [10, 11]; @@ -45,7 +45,7 @@ export class TabPaneTimeParallel extends BaseElement { private rightEndNs: number = 0; private midCores: Array = []; private bigCores: Array = []; - private smallCores: Array = []; + private littleCores: Array = []; private initStatus: boolean = true; set data(threadStatesParam: SelectionParam) { @@ -70,7 +70,7 @@ export class TabPaneTimeParallel extends BaseElement { if (this.initStatus) { this.initDefaultConfig(); this.initStatus = false; - this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.bigCores); + this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.littleCores, this.midCores, this.bigCores); } }; this.litPopoverEl!.querySelector('.confirm-button')!.addEventListener('click', (e: unknown) => { @@ -85,7 +85,7 @@ export class TabPaneTimeParallel extends BaseElement { // @ts-ignore this.litPopoverEl!.visible = false; //当大中小核未分组时,默认查询所有核 - if (!this.midCores.length && !this.bigCores.length && !this.smallCores.length) { + if (!this.midCores.length && !this.bigCores.length && !this.littleCores.length) { this.assignAllCore(); } else { this.assignGroupCore(); @@ -142,11 +142,11 @@ export class TabPaneTimeParallel extends BaseElement { initDefaultConfig(): void { if (this.initStatus) { if (Utils.getInstance().getWinCpuCount() === CORE_NUM) { - this.smallCores = [...SMALL_CPU_NUM]; + this.littleCores = [...LITTLE_CPU_NUM]; this.midCores = [...MID_CPU_NUM12]; this.bigCores = [...BIG_CPU_NUM12]; } else { - this.smallCores = []; + this.littleCores = []; this.midCores = []; this.bigCores = []; } @@ -168,7 +168,7 @@ export class TabPaneTimeParallel extends BaseElement { let cpuObj: Object = { 'B': this.bigCores, 'M': this.midCores, - 'S': this.smallCores + 'L': this.littleCores }; for (const [key, val] of Object.entries(cpuObj)) { if (val.length) { diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts index 9533835a..5c3af47b 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts @@ -24,7 +24,7 @@ export class ProcedureLogicWorkerSchedulingAnalysis extends LogicHandler { freq: number = 0; bigCores: Array = []; midCores: Array = []; - smallCores: Array = []; + littleCores: Array = []; cpuFreqMap: Map> = new Map>(); cpuIdle0Map: Map> = new Map>(); threadMap: Map = new Map(); @@ -34,7 +34,7 @@ export class ProcedureLogicWorkerSchedulingAnalysis extends LogicHandler { clearAll(): void { this.bigCores.length = 0; this.midCores.length = 0; - this.smallCores.length = 0; + this.littleCores.length = 0; this.cpuAnalysisMap.clear(); this.threadMap.clear(); this.processMap.clear(); @@ -283,9 +283,9 @@ export class ProcedureLogicWorkerSchedulingAnalysis extends LogicHandler { //@ts-ignore this.midCores = data.params.midCores || []; //@ts-ignore - this.smallCores = data.params.smallCores || []; + this.littleCores = data.params.littleCores || []; //@ts-ignore - this.queryThreadCpuUsage(data.params.bigCores || [], data.params.midCores || [], data.params.smallCores || []); + this.queryThreadCpuUsage(data.params.bigCores || [], data.params.midCores || [], data.params.littleCores || []); } } private schedulingThreadRunTime(data: { id: string; action: string; params: unknown }): void { @@ -526,7 +526,7 @@ where cmf.name = 'cpu_idle' and value != 0 ); } - queryThreadCpuUsage(bigCores: number[], midCores: number[], smallCores: number[]): void { + queryThreadCpuUsage(bigCores: number[], midCores: number[], littleCores: number[]): void { let sql = ` select A.pid,A.tid,A.cpu, sum(A.dur) as total @@ -919,7 +919,7 @@ where cpu not null }) .slice(0, 20); } - private filterThreadCpuUsageArr(arr: unknown, sumBig: number, sumMid: number, sumSmall: number): void { + private filterThreadCpuUsageArr(arr: unknown, sumBig: number, sumMid: number, sumLittle: number): void { //@ts-ignore return arr.reduce((group: unknown, item: { total: number; pid: number; tid: number; cpu: number }) => { const { tid } = item; @@ -934,9 +934,9 @@ where cpu not null cpuType = 'mid'; sumMid += item.total; } - if (this.smallCores.includes(item.cpu)) { - cpuType = 'small'; - sumSmall += item.total; + if (this.littleCores.includes(item.cpu)) { + cpuType = 'little'; + sumLittle += item.total; } if (tidObj) { //@ts-ignore @@ -944,7 +944,7 @@ where cpu not null //@ts-ignore tidObj.mid += cpuType === 'mid' ? item.total : 0; //@ts-ignore - tidObj.small += cpuType === 'small' ? item.total : 0; + tidObj.little += cpuType === 'little' ? item.total : 0; //@ts-ignore tidObj.total += item.total; //@ts-ignore @@ -959,7 +959,7 @@ where cpu not null total: item.total, big: cpuType === 'big' ? item.total : 0, mid: cpuType === 'mid' ? item.total : 0, - small: cpuType === 'small' ? item.total : 0, + little: cpuType === 'little' ? item.total : 0, }; //@ts-ignore group[`${tid}`][`cpu${item.cpu}`] = item.total; @@ -971,8 +971,8 @@ where cpu not null private handlerThreadCpuUsageData(arr: Array): Map { let sumBig = 0; let sumMid = 0; - let sumSmall = 0; - let reduceObj = this.filterThreadCpuUsageArr(arr, sumBig, sumMid, sumSmall); + let sumLittle = 0; + let reduceObj = this.filterThreadCpuUsageArr(arr, sumBig, sumMid, sumLittle); // @ts-ignore let source: unknown[] = Object.values(reduceObj); for (let obj of source) { @@ -981,13 +981,13 @@ where cpu not null // @ts-ignore obj.midPercent = sumMid === 0 ? '0' : ((obj.mid / sumMid) * 100).toFixed(2); // @ts-ignore - obj.smallPercent = sumSmall === 0 ? '0' : ((obj.small / sumSmall) * 100).toFixed(2); + obj.littlePercent = sumLittle === 0 ? '0' : ((obj.little / sumLittle) * 100).toFixed(2); // @ts-ignore obj.bigTimeStr = getProbablyTime(obj.big); // @ts-ignore obj.midTimeStr = getProbablyTime(obj.mid); // @ts-ignore - obj.smallTimeStr = getProbablyTime(obj.small); + obj.littleTimeStr = getProbablyTime(obj.little); } let map: Map> = new Map>(); // @ts-ignore @@ -997,7 +997,7 @@ where cpu not null // @ts-ignore map.set('mid', source.sort((a, b) => b.mid - a.mid).slice(0, 20)); // @ts-ignore - map.set('small', source.sort((a, b) => b.small - a.small).slice(0, 20)); + map.set('little', source.sort((a, b) => b.little - a.little).slice(0, 20)); // @ts-ignore return map; } @@ -1115,13 +1115,13 @@ export class ThreadCpuUsage { total: number = 0; big: number = 0; mid: number = 0; - small: number = 0; + little: number = 0; bigPercent: string = ''; bigTimeStr: string = ''; midPercent: string = ''; midTimeStr: string = ''; - smallPercent: string = ''; - smallTimeStr: string = ''; + littlePercent: string = ''; + littleTimeStr: string = ''; } export class FreqThread { -- Gitee From 3e39a6076f65b420a7b501f1575895eaec108455 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Fri, 4 Jul 2025 14:05:40 +0800 Subject: [PATCH 45/51] =?UTF-8?q?fix:=E5=88=87=E6=8D=A2dify=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- .../statistics/util/SpStatisticsHttpUtil.ts | 5 ++- ide/src/trace/component/SpAiAnalysisPage.ts | 41 ++++++++----------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts index 36e96531..d00889ca 100644 --- a/ide/src/statistics/util/SpStatisticsHttpUtil.ts +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -216,7 +216,8 @@ export class SpStatisticsHttpUtil { method: 'post', signal: controller.signal, headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'Authorization': 'Bearer app-KzQMtbV8efNFh3C33kCbte27' }, body: JSON.stringify(requestBody) }).then(async res => { @@ -224,7 +225,7 @@ export class SpStatisticsHttpUtil { if (res.status === 200) { let resp = await res.text(); let resj = await JSON.parse(resp); - response.data = resj.reason && resj.reason === 'ok' ? resj.chatbot_reply : '服务器异常,请稍后再试'; + response.data = resj.event && resj.event === 'message' ? resj.answer : '服务器异常,请稍后再试'; } else { response.data = '服务器请求失败'; diff --git a/ide/src/trace/component/SpAiAnalysisPage.ts b/ide/src/trace/component/SpAiAnalysisPage.ts index 3742c462..ab6c5407 100644 --- a/ide/src/trace/component/SpAiAnalysisPage.ts +++ b/ide/src/trace/component/SpAiAnalysisPage.ts @@ -169,9 +169,9 @@ export class SpAiAnalysisPage extends BaseElement { // 给右边栏添加点击事件 // @ts-ignore - rightBarGroup.forEach((barItem: unknown, index: number) => { + rightBarGroup.forEach((barItem: unknown, index: number) => { // @ts-ignore - barItem.barEl.addEventListener('click', (ev: Event) => { + barItem.barEl.addEventListener('click', (ev: Event) => { // @ts-ignore if (barItem.isMustLoadedTrace && !SpApplication.isTraceLoaded) { let importTraceTips = '请先导入trace,再使用诊断功能'; @@ -180,26 +180,26 @@ export class SpAiAnalysisPage extends BaseElement { return; } // this.tipsContent!.style.display = this.isNodata && barItem.barFlag === 'detect' ? 'flex' : 'none'; - this.tipsContainer!.style.display = 'none'; + this.tipsContainer!.style.display = 'none'; // @ts-ignore - this.showPageFlag = barItem.barFlag; + this.showPageFlag = barItem.barFlag; // @ts-ignore - barItem.imgEl.src = barItem.activeImg; + barItem.imgEl.src = barItem.activeImg; // @ts-ignore - barItem.barEl.classList.add('active'); + barItem.barEl.classList.add('active'); // @ts-ignore - barItem.showPage.style.display = 'block'; + barItem.showPage.style.display = 'block'; // @ts-ignore if (this.tipContentArr.indexOf(barItem.barFlag) > -1) { this.tipsContainer!.style.display = 'flex'; - } + } // @ts-ignore for (let i = 0; i < rightBarGroup.length; i++) { - if (i !== index) { + if (i !== index) { // @ts-ignore - rightBarGroup[i].barEl.classList.remove('active'); + rightBarGroup[i].barEl.classList.remove('active'); // @ts-ignore - rightBarGroup[i].imgEl.src = rightBarGroup[i].img; + rightBarGroup[i].imgEl.src = rightBarGroup[i].img; // @ts-ignore rightBarGroup[i].showPage.style.display = 'none'; } @@ -396,26 +396,21 @@ export class SpAiAnalysisPage extends BaseElement { this.createChatBox(); this.createAiChatBox('AI智能分析中...'); this.q_a_window!.scrollTop = this.q_a_window!.scrollHeight; - // 没有token - if (this.chatToken === '') { - await this.getToken90Min('aiTakeToken', true); - } - if (this.chatToken !== '') { - this.answer(); - } + this.answer(); } } // ai对话 async answer(): Promise { let requestBody = { - token: this.chatToken, - question: this.question, - collection: 'smart_perf_test', - scope: 'smartperf' + 'inputs': {}, + 'query': this.question, + 'response_mode': 'blocking', + 'conversation_id': '', + 'user': 'abc-123' }; - await SpStatisticsHttpUtil.askAi(requestBody, 'aiAsk').then(res => { + await SpStatisticsHttpUtil.askAi(requestBody, 'difyAsk').then(res => { if (res.status === 200) { SpStatisticsHttpUtil.generalRecord('AI_statistic', 'large_model_q&a', []); } -- Gitee From 00e9afc502ffbdf85dbf9d5401f46809cc9cb71c Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 7 Jul 2025 15:19:53 +0800 Subject: [PATCH 46/51] fix:update Dify Signed-off-by: danghongquan --- ide/src/statistics/util/SpStatisticsHttpUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts index d00889ca..a065c16f 100644 --- a/ide/src/statistics/util/SpStatisticsHttpUtil.ts +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -217,7 +217,7 @@ export class SpStatisticsHttpUtil { signal: controller.signal, headers: { 'Content-Type': 'application/json', - 'Authorization': 'Bearer app-KzQMtbV8efNFh3C33kCbte27' + 'Authorization': 'Bearer app-6mUvoj5WO5hRaMVLBzV0oCVI' }, body: JSON.stringify(requestBody) }).then(async res => { -- Gitee From 17d75b29ac41d50f8c832cb31d40dd6320d983b9 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Tue, 1 Jul 2025 15:41:33 +0800 Subject: [PATCH 47/51] add build for ohos arm. Signed-off-by: JustinYT --- .gitignore | 1 + trace_streamer/build.sh | 5 ++ trace_streamer/build/dl_ohos_sdk.sh | 58 +++++++++++++++++++ trace_streamer/build/protoc.sh | 6 ++ trace_streamer/build/ts.gni | 2 + trace_streamer/build_operator.sh | 2 +- trace_streamer/doc/compile_trace_streamer.md | 2 + trace_streamer/gn/BUILD.gn | 26 +++++++-- trace_streamer/gn/CONFIG.gn | 5 ++ trace_streamer/gn/toolchain/BUILD.gn | 12 ++++ .../prebuilts/patch_llvm/llvm.patch | 36 +++++++++--- .../offline_symbolization_filter.h | 2 +- .../src/parser/ebpf_parser/ebpf_data_reader.h | 2 +- .../parser/ebpf_parser/ebpf_data_structure.h | 2 +- .../src/parser/ebpf_parser/ebpf_splitter.h | 2 +- trace_streamer/src/version.cpp | 4 +- 16 files changed, 147 insertions(+), 20 deletions(-) create mode 100755 trace_streamer/build/dl_ohos_sdk.sh diff --git a/.gitignore b/.gitignore index 6ec0ed2f..9bfb72ff 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ trace_streamer/third_party trace_streamer/tools trace_streamer/compile_commands.json trace_streamer/*.tar.gz +trace_streamer/*.tar.xz trace_streamer/*.zip ts_tmp.perf.data trace_streamer/.cache diff --git a/trace_streamer/build.sh b/trace_streamer/build.sh index 726b25fd..0228452e 100755 --- a/trace_streamer/build.sh +++ b/trace_streamer/build.sh @@ -16,6 +16,7 @@ PARAMS=$* SOURCE="${BASH_SOURCE[0]}" cd "$(dirname "${SOURCE}")" . build/build_stanalone_plugins.sh +. build/dl_ohos_sdk.sh set_enable_plugin_array "true" set_enable_extend_plugin_array "false" set_enable_macro_switch_array "false" @@ -60,6 +61,10 @@ if [ "$#" -ne "0" ];then fi target="$1" fi + if [ "$1" == "ohos" ];then + prepare_ohos + target_os="$1" + fi if [ "$1" == "test" ];then target="test" set_enable_plugin_array "true" diff --git a/trace_streamer/build/dl_ohos_sdk.sh b/trace_streamer/build/dl_ohos_sdk.sh new file mode 100755 index 00000000..fff146d0 --- /dev/null +++ b/trace_streamer/build/dl_ohos_sdk.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. +# 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. +set -e +function dl_ohos_sdk() { + if [ ! -d "tools/ohos-sdk" ];then + echo "you need ohos-sdk to compile ohos" + if [ ! -d "tools" ];then + mkdir tools + fi + if [ ! -d "tools/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu" ];then + curl https://repo.huaweicloud.com/openharmony/compiler/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/1.0/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz --output gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz + tar Jxvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz --directory=tools/ + fi + if [ ! -d "tools/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi" ];then + curl https://repo.huaweicloud.com/openharmony/compiler/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/1.0/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz --output gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz + tar zxvf gcc-linaro-7.5.0-arm-linux-gnueabi.tar.gz --directory=tools/ + fi + if [ ! -d "tools/ohos-sdk" ];then + curl http://download.ci.openharmony.cn/version/Daily_Version/ohos-sdk-full-linux/20250623_041115/version-Daily_Version-ohos-sdk-full-linux-20250623_041115-ohos-sdk-full-linux.tar.gz --output ohos-sdk.tar.gz + tar -xvf ohos-sdk.tar.gz --directory=tools/ + cd tools/ohos-sdk/linux + for zipfile in *.zip; do + echo "unzip:$zipfile" + unzip -o "$zipfile" + done + cd - + cp tools/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/lib/gcc/aarch64-linux-gnu/7.5.0/libgcc.a tools/ohos-sdk/linux/native/sysroot/usr/lib/aarch64-linux-ohos + cp tools/prebuilts_gcc_linux-x86_arm_gcc-linaro-7.5.0-arm-linux-gnueabi/lib/gcc/arm-linux-gnueabi/7.5.0/libgcc.a tools/ohos-sdk/linux/native/sysroot/usr/lib/arm-linux-ohos + fi + fi +} +function prepare_ohos() { + if [ ! -e "out/linux/protoc" ]; then + echo "out/linux/protoc not found, need to build:" + ./build.sh linux -m addr2line + fi + if [ ! -d "out/ohos" ]; then + mkdir -p out/ohos + fi + if [ ! -d "out/ohos_debug" ]; then + mkdir -p out/ohos_debug + fi + rm -rf out/ohos/gen out/ohos_debug/gen/ + cp -rf out/linux/gen out/ohos/ + cp -rf out/linux/gen out/ohos_debug/ + dl_ohos_sdk +} \ No newline at end of file diff --git a/trace_streamer/build/protoc.sh b/trace_streamer/build/protoc.sh index e14750bc..4f120efa 100755 --- a/trace_streamer/build/protoc.sh +++ b/trace_streamer/build/protoc.sh @@ -23,6 +23,12 @@ if [[ "$3" == *"developtools"* ]]; then PROJECT_TOP=$(realpath $THIS_DIR/../../../..) fi +if [[ "$2" == "out/ohos" || "$2" == "out/ohos_debug" ]]; then + if [[ -e "$PROJECT_TOP/out/ohos/gen/cpp/src/protos/services/common_types.pb.cc" || -e "$PROJECT_TOP/out/ohos_debug/gen/cpp/src/protos/services/common_types.pb.cc" ]]; then + exit 0 + fi +fi + OHOS_X64_OUT=$PROJECT_TOP/$2/ LIBCXX_X64_OUT=$PROJECT_TOP/$1/ndk/libcxx/linux_x86_64 SUBSYS_X64_OUT=$PROJECT_TOP/$2/$TAIL_DIR diff --git a/trace_streamer/build/ts.gni b/trace_streamer/build/ts.gni index 4e7b0ba7..6e117162 100644 --- a/trace_streamer/build/ts.gni +++ b/trace_streamer/build/ts.gni @@ -68,6 +68,8 @@ THIRD_PARTY = "//third_party" kernel_version = "." LLVM_ROOT = "//llvm" +TOOLS_DIR = rebase_path("//tools") + OHOS_TRACE_STREAMER_DIR_PROTOC = get_path_info("./protoc.sh", "abspath") if (target_os == "windows") { diff --git a/trace_streamer/build_operator.sh b/trace_streamer/build_operator.sh index 656c8ee4..dc608d79 100755 --- a/trace_streamer/build_operator.sh +++ b/trace_streamer/build_operator.sh @@ -16,7 +16,7 @@ echo "target_operator = $target_operator" if [ "$target" != "trace" ] && [ "$target" != "linux" ] && [ "$target" != "windows" ] && [ "$target" != "macx" ] && [ "$target" != "trace_streamer" ] && [ "$target" != "wasm" ] && [ "$target" != "test" ] && [ "$target" != "spb" ] && [ "$target" != "fuzz" ] && - [ "$target" != "protoc" ] && [ "$target" != "sdkdemo" ] && [ "$target" != "sdkdemotest" ];then + [ "$target" != "protoc" ] && [ "$target" != "sdkdemo" ] && [ "$target" != "sdkdemotest" ] && [ "$target" != "ohos" ];then echo "failed" exit fi diff --git a/trace_streamer/doc/compile_trace_streamer.md b/trace_streamer/doc/compile_trace_streamer.md index 6002bb43..d7cdae18 100755 --- a/trace_streamer/doc/compile_trace_streamer.md +++ b/trace_streamer/doc/compile_trace_streamer.md @@ -15,6 +15,7 @@ TraceStreamer可以编译为命令行下的可执行程序,或者WebAssembly |linux |clang/clang++| 16.0.6 | | macx |clang/clang++| 14.0.3 | |windows |gcc.exe/g++.exe| gcc version 12.1.0 (x86_64-posix-sjlj-rev3, Built by MinGW-W64 project)| +|ohos(linux下编译) |ohos-sdk clang/clang++| 15.0.4 | |wasm(linux下编译) |emcc/em++| 3.1.12| 对于wasm环境(目前只支持linux下编译),build.sh会自行配置环境。 @@ -32,6 +33,7 @@ TraceStreamer可以编译为命令行下的可执行程序,或者WebAssembly |linux |out/linux| out/linux_debug| trace_streamer | macx |out/macx| out/macx_debug |trace_streamer |windows |out/windows| out/windows_debug|trace_streamer +|ohos(linux下编译) |out/ohos| out/ohos_debug|trace_streamer |wasm(linux下编译) |-|out/wasm|trace_streamer_builtin.wasm和trace_streamer_builtin.js #### 快速编译WebAssembly版本 diff --git a/trace_streamer/gn/BUILD.gn b/trace_streamer/gn/BUILD.gn index 9cd142f5..c30d5c84 100644 --- a/trace_streamer/gn/BUILD.gn +++ b/trace_streamer/gn/BUILD.gn @@ -139,7 +139,7 @@ config("default") { if (target_os == "windows") { cflags += [ "-D target_cpu_x86_64" ] - } else if (is_linux || is_mac) { + } else if (is_linux || is_mac || is_ohos) { cflags += [ "-Wa,--noexecstack", "-fcolor-diagnostics", @@ -152,7 +152,7 @@ config("default") { "-fstack-protector-all", "-D_FORTIFY_SOURCE=2 -O2", "-D target_cpu_x64", - "-D target_cpu_x86_64", + "-D target_cpu_x86_64", # for hiperf "-DHAVE_CONFIG_H", "-DCC_IS_CLANG", ] @@ -203,7 +203,7 @@ config("default") { libs += [ "ws2_32" ] cflags += [ "-Wno-attributes" ] } - if (is_linux) { + if (is_linux || is_ohos) { cflags += [ "-D is_linux=true" ] } if (is_mac) { @@ -231,11 +231,16 @@ config("release") { ldflags = [ "-fstack-protector" ] if (!is_mac) { ldflags += [ "-Wl,-O3" ] - if (!is_win) { + if (!is_win && !is_ohos) { ldflags += [ "-fuse-ld=gold", "-Wl,--gc-sections", ] + } else if (is_ohos) { + ldflags += [ + "-fuse-ld=${TOOLS_DIR}/ohos-sdk/linux/native/llvm/bin/ld.lld", + "-lgcc", + ] } } @@ -266,10 +271,19 @@ config("executable") { "-Wl,--disable-new-dtags", "-Wl,-z,noexecstack", "-lrt", - "-fuse-ld=gold", "-Wl,-z,now", "-Wl,-z,relro", ] + if (is_ohos) { + ldflags += [ + "-fuse-ld=${TOOLS_DIR}/ohos-sdk/linux/native/llvm/bin/ld.lld", + "-lgcc", + ] + } else { + ldflags += [ + "-fuse-ld=gold", + ] + } } if (!is_mac && !use_wasm) { ldflags += [ "-fpie" ] @@ -318,7 +332,7 @@ config("ts_config") { libs = [ "wsock32" ] libs += [ "ws2_32" ] } - if (is_linux) { + if (is_linux || is_ohos) { cflags += [ "-D is_linux=1" ] } if (!use_wasm && !is_win && !is_mac && !is_test && !is_mingw) { diff --git a/trace_streamer/gn/CONFIG.gn b/trace_streamer/gn/CONFIG.gn index 52dfaee2..98b7fd07 100644 --- a/trace_streamer/gn/CONFIG.gn +++ b/trace_streamer/gn/CONFIG.gn @@ -12,6 +12,7 @@ # limitations under the License. is_win = false is_linux = false +is_ohos = false is_mac = false is_protoc = false is_mingw = false @@ -50,6 +51,10 @@ if (target_os == "linux") { is_mingw = true current_cpu = target_cpu current_os = host_os +} else if (target_os == "ohos") { + is_ohos = true + current_cpu = target_cpu + current_os = host_os } else { print("unknown platform " + target_os) exit(-1) diff --git a/trace_streamer/gn/toolchain/BUILD.gn b/trace_streamer/gn/toolchain/BUILD.gn index 91168840..bf2c8889 100644 --- a/trace_streamer/gn/toolchain/BUILD.gn +++ b/trace_streamer/gn/toolchain/BUILD.gn @@ -27,6 +27,15 @@ declare_args() { extra_asmflags = "" asm = "gcc.exe" pic = "" + } else if (target_os == "ohos") { + # --target=arm-linux-ohos for arm32, or --target=aarch64-linux-ohos for arm64 + OHOS_TARGET_ARCH = "--target=arm-linux-ohos" + cc = "../../tools/ohos-sdk/linux/native/llvm/bin/clang $OHOS_TARGET_ARCH" + cxx = "../../tools/ohos-sdk/linux/native/llvm/bin/clang++ $OHOS_TARGET_ARCH" + pic = "-fPIC" + rebuild_string = "" + extra_asmflags = "" + asm = "../../tools/ohos-sdk/linux/native/llvm/bin/clang" } if (use_wasm == true) { print("make_wasm") @@ -168,6 +177,9 @@ toolchain("gcc_like") { } tool("alink") { rspfile = "{{output}}.rsp" # this must be defined + if (is_ohos) { + ar = "../../tools/ohos-sdk/linux/native/llvm/bin/llvm-ar" + } if (is_mac) { rspfile_content = "{{inputs_newline}}" command = "rm -f {{output}} && libtool -static {{arflags}} -filelist $rspfile -o {{output}}" diff --git a/trace_streamer/prebuilts/patch_llvm/llvm.patch b/trace_streamer/prebuilts/patch_llvm/llvm.patch index fcde9776..71f9c23d 100644 --- a/trace_streamer/prebuilts/patch_llvm/llvm.patch +++ b/trace_streamer/prebuilts/patch_llvm/llvm.patch @@ -1,3 +1,5 @@ +diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp +index 39b7bdb7e..96be82f01 100644 --- a/llvm/lib/Support/Host.cpp +++ b/llvm/lib/Support/Host.cpp @@ -518,7 +518,7 @@ static bool isCpuIdSupported() { @@ -28,7 +30,7 @@ // directly because older assemblers do not include support for xgetbv and // there is no easy way to conditionally compile based on the assembler used. diff --git a/llvm/utils/gn/build/buildflags.gni b/llvm/utils/gn/build/buildflags.gni -index ca43a2499edc..bea51ce38990 100644 +index ca43a2499..bea51ce38 100644 --- a/llvm/utils/gn/build/buildflags.gni +++ b/llvm/utils/gn/build/buildflags.gni @@ -1,6 +1,8 @@ @@ -42,7 +44,7 @@ index ca43a2499edc..bea51ce38990 100644 # Whether to build with tsan. use_tsan = false diff --git a/llvm/utils/gn/build/compiled_action.gni b/llvm/utils/gn/build/compiled_action.gni -index 697fe3de2a9e..ad3d177edaf7 100644 +index 697fe3de2..ad3d177ed 100644 --- a/llvm/utils/gn/build/compiled_action.gni +++ b/llvm/utils/gn/build/compiled_action.gni @@ -64,8 +64,13 @@ template("compiled_action") { @@ -62,7 +64,7 @@ index 697fe3de2a9e..ad3d177edaf7 100644 script = "//llvm/utils/gn/build/run_built_binary.py" args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args diff --git a/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn b/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn -index 897364f00741..b540838dd3b2 100644 +index 897364f00..b540838dd 100644 --- a/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn @@ -50,7 +50,11 @@ declare_args() { @@ -125,8 +127,31 @@ index 897364f00741..b540838dd3b2 100644 "HAVE_STRERROR_R=1", "HAVE_SYSCONF=1", "HAVE_SYS_IOCTL_H=1", +diff --git a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn +index 7a864464a..83b0d6d31 100644 +--- a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn ++++ b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn +@@ -5,14 +5,16 @@ static_library("IR") { + public_deps = [ + # Must be public_dep because IR's public headers include llvm-config.h. + "//llvm/include/llvm/Config:llvm-config", +- "//llvm/include/llvm/IR:public_tablegen", + ] + deps = [ +- "//llvm/include/llvm/IR:IntrinsicImpl", + "//llvm/lib/BinaryFormat", + "//llvm/lib/Remarks", + "//llvm/lib/Support", + ] ++ if (!is_ohos) { ++ public_deps += [ "//llvm/include/llvm/IR:public_tablegen" ] ++ deps += [ "//llvm/include/llvm/IR:IntrinsicImpl" ] ++ } + sources = [ + "AbstractCallSite.cpp", + "AsmWriter.cpp", diff --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn -index 56d5b2ce7dc3..827184b7a5e0 100644 +index 56d5b2ce7..7737612f0 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn @@ -1,13 +1,21 @@ @@ -171,6 +196,3 @@ index 56d5b2ce7dc3..827184b7a5e0 100644 ldflags = [ "-delayload:ole32.dll", "-delayload:shell32.dll", --- -2.25.1 - diff --git a/trace_streamer/src/filter/hook_filter/offline_symbolization_filter.h b/trace_streamer/src/filter/hook_filter/offline_symbolization_filter.h index aa73e9ad..cad1c0e2 100644 --- a/trace_streamer/src/filter/hook_filter/offline_symbolization_filter.h +++ b/trace_streamer/src/filter/hook_filter/offline_symbolization_filter.h @@ -16,7 +16,7 @@ #ifndef OFFLINE_SYMBOLIZATION_FILTER_H #define OFFLINE_SYMBOLIZATION_FILTER_H #include "double_map.h" -#ifndef is_linux +#if is_mingw || is_mac #include "dfx_nonlinux_define.h" #else #include diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h index 299b4439..7bd1b431 100644 --- a/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h @@ -15,7 +15,7 @@ #ifndef EBPF_DATA_READER_H #define EBPF_DATA_READER_H -#ifndef is_linux +#if is_mingw || is_mac #include "dfx_nonlinux_define.h" #else #include diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_structure.h b/trace_streamer/src/parser/ebpf_parser/ebpf_data_structure.h index 42acf434..c29b9d29 100644 --- a/trace_streamer/src/parser/ebpf_parser/ebpf_data_structure.h +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_structure.h @@ -14,7 +14,7 @@ */ #ifndef EBPF_DATA_STD_TYPE_H #define EBPF_DATA_STD_TYPE_H -#ifndef is_linux +#if is_mingw || is_mac #include "dfx_nonlinux_define.h" #else #include diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_splitter.h b/trace_streamer/src/parser/ebpf_parser/ebpf_splitter.h index cb60a076..e374a5e3 100644 --- a/trace_streamer/src/parser/ebpf_parser/ebpf_splitter.h +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_splitter.h @@ -15,7 +15,7 @@ #ifndef EBPF_SPLITTER_H #define EBPF_SPLITTER_H -#ifndef is_linux +#if is_mingw || is_mac #include "dfx_nonlinux_define.h" #else #include diff --git a/trace_streamer/src/version.cpp b/trace_streamer/src/version.cpp index dd009f81..2bcfc88d 100644 --- a/trace_streamer/src/version.cpp +++ b/trace_streamer/src/version.cpp @@ -17,7 +17,7 @@ namespace SysTuning { namespace TraceStreamer { size_t g_loadSize = 0; size_t g_fileSize = 0; -const std::string TRACE_STREAMER_VERSION = "4.3.6"; // version -const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/6/25"; // publish datetime +const std::string TRACE_STREAMER_VERSION = "4.3.7"; // version +const std::string TRACE_STREAMER_PUBLISH_VERSION = "2025/07/01"; // publish datetime } // namespace TraceStreamer } // namespace SysTuning -- Gitee From 42aff711098b1d910f12f29fda1a47bd4ee93456 Mon Sep 17 00:00:00 2001 From: JustinYT Date: Fri, 11 Jul 2025 17:13:19 +0800 Subject: [PATCH 48/51] =?UTF-8?q?=E9=80=82=E9=85=8DT-power=E9=9C=80?= =?UTF-8?q?=E6=B1=82=EF=BC=8C=E6=94=AF=E6=8C=81iframe=E5=B5=8C=E5=85=A5hos?= =?UTF-8?q?t,db=E5=AF=BC=E5=87=BA=E5=88=B0t-power=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: JustinYT --- ide/src/trace/SpApplication.ts | 9 +++++-- ide/src/trace/SpApplicationPublicFunc.ts | 26 ++++++++++++++++++++- ide/src/trace/component/trace/base/Utils.ts | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts index 0288314c..b42b8c81 100644 --- a/ide/src/trace/SpApplication.ts +++ b/ide/src/trace/SpApplication.ts @@ -67,6 +67,7 @@ import './component/SpKeyboard'; import { parseKeyPathJson } from './component/Utils'; import { Utils } from './component/trace/base/Utils'; import { + addExportDBToParentEvent, applicationHtml, clearTraceFileCache, findFreeSizeAlgorithm, @@ -76,7 +77,7 @@ import { isZlibFile, postLog, readTraceFileBuffer, - TraceMode, + TraceMode } from './SpApplicationPublicFunc'; import { queryExistFtrace } from './database/sql/SqlLite.sql'; import '../base-ui/chart/scatter/LitChartScatter'; @@ -1328,16 +1329,19 @@ export class SpApplication extends BaseElement { SpApplication.isTraceLoaded = true; if (!isDistributed) { this.importConfigDiv!.style.display = Utils.getInstance().getSchedSliceMap().size > 0 ? 'block' : 'none'; - } + } this.showContent(this.spSystemTrace!); this.litSearch!.setPercent('', 101); this.chartFilter!.setAttribute('mode', ''); this.freshMenuDisable(false); + Utils.currentTraceName = fileName; } else { + info('loadDatabaseArrayBuffer failed'); //@ts-ignore this.litSearch!.setPercent(res.msg || 'This File is not supported!', -1); this.resetMenus(); + Utils.currentTraceName = ''; this.freshMenuDisable(false); } this.progressEL!.loading = false; @@ -2087,6 +2091,7 @@ export class SpApplication extends BaseElement { // 鼠标拖动改变大小 this.aiPageResize(); + addExportDBToParentEvent(); } private aiPageResize(): void { diff --git a/ide/src/trace/SpApplicationPublicFunc.ts b/ide/src/trace/SpApplicationPublicFunc.ts index 6c366a72..bb233089 100644 --- a/ide/src/trace/SpApplicationPublicFunc.ts +++ b/ide/src/trace/SpApplicationPublicFunc.ts @@ -13,7 +13,8 @@ * limitations under the License. */ -import { getThreadPoolTraceBufferCacheKey } from './database/SqlLite'; +import { Utils as TraceUtil } from './component/trace/base/Utils'; +import { getThreadPoolTraceBufferCacheKey, threadPool } from './database/SqlLite'; export enum TraceMode { NORMAL, @@ -590,4 +591,27 @@ export function isZlibFile(uint8Array: Uint8Array): boolean { } } return true; +} + +/** + * 外部交互,向外传输db文件 + */ +export function addExportDBToParentEvent() { + window.addEventListener('message', e => { + if (e.data.name == 'exportDbToParent') { + threadPool.submit('download-db', '', {}, async (reqBufferDB: ArrayBuffer) => { + if (reqBufferDB && reqBufferDB.byteLength > 0) { + window.parent.postMessage({ + name: `${(TraceUtil.currentTraceName || 'trace').split('.')[0]}.db`, + data: reqBufferDB + }, '*'); + } else { + window.parent.postMessage({ + name: `暂无数据`, + data: null + }, '*'); + } + }, 'download-db'); + } + }); } \ No newline at end of file diff --git a/ide/src/trace/component/trace/base/Utils.ts b/ide/src/trace/component/trace/base/Utils.ts index e47afafd..f8ebc2fb 100644 --- a/ide/src/trace/component/trace/base/Utils.ts +++ b/ide/src/trace/component/trace/base/Utils.ts @@ -24,6 +24,7 @@ export class Utils { static currentTraceMode: TraceMode = TraceMode.NORMAL; static distributedTrace: string[] = []; static isRangeSelectRefresh: boolean = false; + static currentTraceName: string = ''; static DMAFENCECAT_MAP: Map< number, { -- Gitee From 336362414e43201ca2475eb56665fdc49d3939cc Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 14 Jul 2025 08:28:11 +0800 Subject: [PATCH 49/51] =?UTF-8?q?fix:AI=E9=97=AE=E7=AD=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: danghongquan --- ide/src/statistics/util/SpStatisticsHttpUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts index a065c16f..74d00971 100644 --- a/ide/src/statistics/util/SpStatisticsHttpUtil.ts +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -217,7 +217,7 @@ export class SpStatisticsHttpUtil { signal: controller.signal, headers: { 'Content-Type': 'application/json', - 'Authorization': 'Bearer app-6mUvoj5WO5hRaMVLBzV0oCVI' + 'Authorization': 'Bearer app-6mUvoj5WO5hRaMVLBzV0oCV1' }, body: JSON.stringify(requestBody) }).then(async res => { -- Gitee From e14607fc6a313160e7d067bd9d527be3e2d0a439 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 14 Jul 2025 08:45:36 +0800 Subject: [PATCH 50/51] fix:Ai Signed-off-by: danghongquan --- ide/src/statistics/util/SpStatisticsHttpUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts index 74d00971..1f7761cc 100644 --- a/ide/src/statistics/util/SpStatisticsHttpUtil.ts +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -217,7 +217,7 @@ export class SpStatisticsHttpUtil { signal: controller.signal, headers: { 'Content-Type': 'application/json', - 'Authorization': 'Bearer app-6mUvoj5WO5hRaMVLBzV0oCV1' + 'Authorization': 'Bearer app-6mUvoj5WO5hRaMVLBzV0oCVl' }, body: JSON.stringify(requestBody) }).then(async res => { -- Gitee From 5249304436d068fcbb330b7a025b2734af2b33c7 Mon Sep 17 00:00:00 2001 From: danghongquan Date: Mon, 14 Jul 2025 17:26:24 +0800 Subject: [PATCH 51/51] fix:heca_freq Signed-off-by: danghongquan --- .../trace/database/data-trafic/ClockDataReceiver.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ide/src/trace/database/data-trafic/ClockDataReceiver.ts b/ide/src/trace/database/data-trafic/ClockDataReceiver.ts index 003775fb..30d84c99 100644 --- a/ide/src/trace/database/data-trafic/ClockDataReceiver.ts +++ b/ide/src/trace/database/data-trafic/ClockDataReceiver.ts @@ -63,10 +63,15 @@ export const chartClockDataSql = (args: Args): string => { export const chartClockDataSqlMem = (args: Args): string => { if (args.sqlType === 'clockFrequency') { return ` - with freq as ( select measure.filter_id, measure.ts, measure.type, measure.value from clock_event_filter - left join measure - where clock_event_filter.name = '${args.clockName}' and clock_event_filter.type = 'clock_set_rate' and clock_event_filter.id = measure.filter_id - order by measure.ts) + with freq as ( select + m.filter_id, + m.ts, + m.type, + m.value from clock_event_filter as c + left join measure as m on c.id = m.filter_id + where c.name = '${args.clockName}' + and c.type = 'clock_set_rate' + order by m.ts) select freq.filter_id as filterId,freq.ts - r.start_ts as startNs,freq.type,freq.value from freq,trace_range r order by startNs; `; } else if (args.sqlType === 'clockState') { -- Gitee