diff --git a/ide/src/trace/bean/FrameChartStruct.ts b/ide/src/trace/bean/FrameChartStruct.ts index cb93632d9c4051aa22f044d4255ae2fe107c1d83..7ac0be0e55a5e1dbff837dc21482d17c54e79215 100644 --- a/ide/src/trace/bean/FrameChartStruct.ts +++ b/ide/src/trace/bean/FrameChartStruct.ts @@ -38,16 +38,19 @@ export class ChartStruct extends BaseStruct { size: number = 0; // 实际size count: number = 0; // 实际count + eventCount: number = 0; dur: number = 0; // 实际dur //搜索后会根据搜索匹配的函数的值赋值给parent searchSize: number = 0; // searchCount: number = 0; searchDur: number = 0; + searchEventCount: number = 0; //点击绘制的size在搜索的基础上,赋值给parent drawSize: number = 0; drawCount: number = 0; drawDur: number = 0; + drawEventCount: number = 0; parent: ChartStruct | undefined; children: Array = []; percent: number = 0; // 0 - 1 该node所占整体的百分比 @@ -64,6 +67,7 @@ export enum ChartMode { Byte, // Native Memory Count, // Perf Duration, // eBpf + EventCount,//cycles } export function setFuncFrame(node: ChartStruct, canvasFrame: Rect, total: number, mode: ChartMode): void { @@ -92,6 +96,9 @@ export function setFuncFrame(node: ChartStruct, canvasFrame: Rect, total: number case ChartMode.Duration: node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvasFrame.width); break; + case ChartMode.EventCount: + node.frame!.width = Math.floor(((node.drawEventCount || node.eventCount) / total) * canvasFrame.width); + break; default: warn('not match ChartMode'); } diff --git a/ide/src/trace/component/chart/FrameChart.ts b/ide/src/trace/component/chart/FrameChart.ts index 69cae06ff70f5787f11851050294a01805e3be1a..86d2ec7313e63fb508cf120104d95ca25ba581ad 100644 --- a/ide/src/trace/component/chart/FrameChart.ts +++ b/ide/src/trace/component/chart/FrameChart.ts @@ -31,11 +31,13 @@ class NodeValue { size: number; count: number; dur: number; + eventCount: number; constructor() { this.size = 0; this.count = 0; this.dur = 0; + this.eventCount = 0; } } @@ -97,6 +99,8 @@ export class FrameChart extends BaseElement { return node.drawCount || node.count; case ChartMode.Duration: return node.drawDur || node.dur; + case ChartMode.EventCount: + return node.drawEventCount || node.eventCount; } } @@ -133,6 +137,7 @@ export class FrameChart extends BaseElement { this.rootNode.count += node.drawCount || node.count; this.rootNode.size += node.drawSize || node.size; this.rootNode.dur += node.drawDur || node.dur; + this.rootNode.eventCount += node.drawEventCount || node.eventCount; node.parent = this.rootNode; } } @@ -167,14 +172,17 @@ export class FrameChart extends BaseElement { node.drawCount = 0; node.drawDur = 0; node.drawSize = 0; + node.drawEventCount = 0; for (let child of node.children) { node.drawCount += child.searchCount; node.drawDur += child.searchDur; node.drawSize += child.searchSize; + node.drawEventCount += child.searchEventCount; } module.count = node.drawCount = node.drawCount || node.count; module.dur = node.drawDur = node.drawDur || node.dur; module.size = node.drawSize = node.drawSize || node.size; + module.eventCount = node.drawEventCount = node.drawEventCount || node.eventCount this.setParentDisplayInfo(node, module, true); this.setChildrenDisplayInfo(node); @@ -198,6 +206,10 @@ export class FrameChart extends BaseElement { currentValue = Utils.getProbablyTime(this.total); currentValuePercent = this.total / this.rootNode.dur; break; + case ChartMode.EventCount: + currentValue = Utils.timeMsFormat2p(this.total * (SpHiPerf.stringResult?.fValue || 1)); + currentValuePercent = this.total / this.rootNode.eventCount; + break; } this.rootNode.symbol = `Root : ${currentValue} (${(currentValuePercent * 100).toFixed(2)}%)`; } @@ -218,6 +230,7 @@ export class FrameChart extends BaseElement { module.size = node.drawSize = node.searchSize = node.size; module.count = node.drawCount = node.searchCount = node.count; module.dur = node.drawDur = node.searchDur = node.dur; + module.eventCount = node.drawEventCount = node.searchEventCount = node.eventCount this.setParentDisplayInfo(node, module, false); calDisplay = false; } @@ -243,15 +256,18 @@ export class FrameChart extends BaseElement { parent.drawCount = module.count; parent.drawDur = module.dur; parent.drawSize = module.size; + parent.drawEventCount = module.eventCount; } else { parent.searchCount += module.count; parent.searchDur += module.dur; parent.searchSize += module.size; + parent.searchEventCount += module.eventCount; // 点击模式下不需要赋值draw value,由点击去 if (!this.isClickMode) { parent.drawDur = parent.searchDur; parent.drawCount = parent.searchCount; parent.drawSize = parent.searchSize; + parent.drawEventCount = parent.searchEventCount; } } this.setParentDisplayInfo(parent, module, isSelect); @@ -271,6 +287,7 @@ export class FrameChart extends BaseElement { children.drawCount = children.searchCount || children.count; children.drawDur = children.searchDur || children.dur; children.drawSize = children.searchSize || children.size; + children.drawEventCount = children.searchEventCount || children.eventCount; this.setChildrenDisplayInfo(children); } } @@ -279,9 +296,11 @@ export class FrameChart extends BaseElement { node.drawCount = 0; node.drawDur = 0; node.drawSize = 0; + node.drawEventCount = 0; node.searchCount = 0; node.searchDur = 0; node.searchSize = 0; + node.searchEventCount = 0; } /** @@ -392,6 +411,11 @@ export class FrameChart extends BaseElement { ((this.total * (SpHiPerf.stringResult?.fValue || 1) * sizeRatio) / 10) * i ); break; + case ChartMode.EventCount: + calibration = Utils.timeMsFormat2p( + ((this.total * (SpHiPerf.stringResult?.fValue || 1) * sizeRatio) / 10) * i + ); + break; case ChartMode.Duration: calibration = Utils.getProbablyTime(((this.total * sizeRatio) / 10) * i); break; @@ -450,10 +474,12 @@ export class FrameChart extends BaseElement { ignore.size += children.drawSize; ignore.count += children.drawCount; ignore.dur += children.drawDur; + ignore.eventCount += children.drawEventCount; } else { ignore.size += children.size; ignore.count += children.count; ignore.dur += children.dur; + ignore.eventCount += children.eventCount; } } } @@ -464,6 +490,8 @@ export class FrameChart extends BaseElement { return ignore.count; case ChartMode.Duration: return ignore.dur; + case ChartMode.EventCount: + return ignore.eventCount; } } @@ -475,6 +503,8 @@ export class FrameChart extends BaseElement { return node.searchCount > 0; case ChartMode.Duration: return node.searchDur > 0; + case ChartMode.EventCount: + return node.searchEventCount > 0; } } @@ -625,6 +655,14 @@ export class FrameChart extends BaseElement { newWidth = this.canvas!.width / (10 / this.total); } break; + case ChartMode.EventCount: + if (Math.round((this.total * sizeRatio) / ratio) <= 10) { + if (this.xPoint === 0) { + return; + } + newWidth = this.canvas!.width / (10 / this.total); + } + break; case ChartMode.Duration: if (Math.round((this.total * sizeRatio) / ratio) <= ms10) { if (this.xPoint === 0) { @@ -787,6 +825,19 @@ export class FrameChart extends BaseElement { Addr: ${hoverNode?.addr}
Duration: ${duration} (${percent}%)`; break; + case ChartMode.EventCount: + const eventCount = this.getNodeValue(hoverNode); + const eventDur = Utils.timeMsFormat2p(eventCount * (SpHiPerf.stringResult?.fValue || 1)); + this.hintContent = ` + Name: ${name}
+ Lib: ${hoverNode?.lib} +
+ Addr: ${hoverNode?.addr} +
+ Dur: ${eventDur} (${percent}%) +
+ EventCount: ${eventCount} (${percent}%)`; + break; } } diff --git a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts index f5d38b3cf9bf3170b273804ce2b78abb1d9c7e21..94489e1267f75fac6e449cfc8494520e1eaaa8cc 100644 --- a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts +++ b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts @@ -21,6 +21,8 @@ import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; import '../../../../base-ui/popover/LitPopoverV.js'; import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox.js'; import { LitSelect } from '../../../../base-ui/select/LitSelect'; +import { queryTransferList } from '../../../database/SqlLite.js'; + export interface FilterData { inputValue: string; @@ -53,9 +55,11 @@ export class TabPaneFilter extends BaseElement { private getCallTree: ((e: any) => void) | undefined; private getCallTreeConstraints: ((e: any) => void) | undefined; private getStatisticsType: ((e: any) => void) | undefined; + private getCallTransfer: ((e: any) => void) | undefined; private cutList: Array | undefined; private libraryList: Array | undefined; + private transferChecked: string | undefined; filterData(type: string, data: object = {}) { return { @@ -89,6 +93,7 @@ export class TabPaneFilter extends BaseElement { this.markButtonEL = this.shadowRoot?.querySelector('#mark'); this.iconEL = this.shadowRoot?.querySelector('#icon'); this.statisticsName = this.shadowRoot?.querySelector('.statistics-name'); + let transferEL = this.shadowRoot?.querySelector('.transfer-text'); this.iconEL!.onclick = (e) => { if (this.iconEL!.name == 'statistics') { this.iconEL!.name = 'menu'; @@ -96,15 +101,21 @@ export class TabPaneFilter extends BaseElement { if (this.getFilter) { this.getFilter(this.filterData('icon')); } + transferEL!.style.display = 'inline'; } else if (this.iconEL!.name == 'menu') { this.iconEL!.name = 'statistics'; this.iconEL!.size = 16; if (this.getFilter) { this.getFilter(this.filterData('icon')); } + transferEL!.style.display = 'none'; } }; + transferEL!.onclick = () => { + this.getTransferList(); + } + this.markButtonEL!.onclick = (e) => { if (this.getFilter) { this.getFilter(this.filterData('mark', { mark: true })); @@ -268,6 +279,10 @@ export class TabPaneFilter extends BaseElement { this.getCallTree = getCallTree; } + getCallTransferData(getCallTransfer: (v: any) => void) { + this.getCallTransfer = getCallTransfer; + } + getCallTreeConstraintsData(getCallTreeConstraints: (v: any) => void) { this.getCallTreeConstraints = getCallTreeConstraints; } @@ -405,6 +420,39 @@ export class TabPaneFilter extends BaseElement { }); } + initializeTreeTransfer() { + let radioList = this.shadowRoot!.querySelectorAll('.radio'); + let divElement = this.shadowRoot!.querySelectorAll('.tree-radio'); + + if(this.transferChecked && this.transferChecked !== 'count') { + radioList![Number(this.transferChecked)].checked = true; + } else if( this.transferChecked && this.transferChecked == 'count') { + radioList![radioList.length -1].checked = true; + } + + divElement!.forEach((divEl, idx) => { + divEl.addEventListener('click', () => { + this.transferChecked = radioList![idx].value; + radioList![idx].checked = true; + if(this.getCallTransfer) { + this.getCallTransfer({ + value: radioList![idx].value + }) + } + }) + }) + } + + refreshTreeTransfer() { + let radioList = this.shadowRoot!.querySelectorAll('.radio'); + if(this.transferChecked && this.transferChecked !== 'count') { + radioList![Number(this.transferChecked)].checked = false; + } else if( this.transferChecked && this.transferChecked == 'count') { + radioList![radioList.length -1].checked = false; + } + this.transferChecked = '' + } + initializeTreeConstraints() { let inputs = this.shadowRoot!.querySelectorAll('.constraints-input'); let check = this.shadowRoot!.querySelector('#constraints-check'); @@ -569,6 +617,19 @@ export class TabPaneFilter extends BaseElement { return data; } + async getTransferList() { + let dataCmd: { id: number; cmdStr: string }[] = (await queryTransferList()) as { id: number; cmdStr: string }[]; + let html = ""; + dataCmd.forEach(item => { + html += `
+ ${item.cmdStr}
` + }); + html +=`
+ Count
` + this.shadowRoot!.querySelector('#transfer-list')!.innerHTML = html; + this.initializeTreeTransfer(); + } + initializeFilterTree(callTree: boolean = true, treeConstraints: boolean = true, mining: boolean = true) { if (callTree) { let row = this.shadowRoot!.querySelectorAll('.tree-check'); @@ -795,6 +856,17 @@ export class TabPaneFilter extends BaseElement { .lit-check-box{ margin-right: 5px; } + .transfer-list{ + display: flex; + flex-derection: column; + } + .tree-radio{ + margin: 5px 0; + cursor: pointer; + } + .radio{ + cursor: pointer; + } Input Filter @@ -823,6 +895,12 @@ export class TabPaneFilter extends BaseElement { Sample Count Filter + + +
+ +
+ Transfer
diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts index 16cc03f897dcd29511b1464c8abb288a37fa2695..6103c7e39b07a95ec1fc338c640064a3ff1312e5 100644 --- a/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts @@ -93,6 +93,35 @@ export class TabpanePerfProfile extends BaseElement { this.perfProfilerFilter.icon = 'block'; } ); + + this.perfProfilerFilter!.getCallTransferData((data: any) => { + perfProfilerSelection.eventTypeId = data.value !== 'count' ? data.value : undefined; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [perfProfilerSelection], + }, + ], + (results: any[]) => { + this.setPerfProfilerLeftTableData(results); + this.perfProfilerList!.recycleDataSource = []; + if(data.value !== 'count') { + this.perfProfileFrameChart!.mode = ChartMode.EventCount; + }else{ + this.perfProfileFrameChart!.mode = ChartMode.Count; + } + + this.perfProfileFrameChart?.updateCanvas(true, initWidth); + this.perfProfileFrameChart!.data = this.perfProfilerDataSource; + this.switchFlameChart(); + this.perfProfilerFilter.icon = 'block'; + }) + }) } getParentTree( diff --git a/ide/src/trace/database/SqlLite.ts b/ide/src/trace/database/SqlLite.ts index d06547eebd89f1f6da97c87a8bb0773ac3a1a745..4ca9187f89b12beccb4303c724cb3b045893998e 100644 --- a/ide/src/trace/database/SqlLite.ts +++ b/ide/src/trace/database/SqlLite.ts @@ -13,7 +13,7 @@ * limitations under the License. */ -import './sql-wasm.js'; +// import './sql-wasm.js'; import { Counter, Fps, SelectionData } from '../bean/BoxSelection.js'; import { WakeupBean } from '../bean/WakeupBean.js'; @@ -5480,3 +5480,9 @@ export const queryTraceType = (): Promise< WHERE m.name = 'source_type';` ); + + export const queryTransferList = (): Promise> => + query( + 'queryTransferList', + `select id, report_value as cmdStr from perf_report where report_type = 'config_name'` + ); diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts index f2e6fcd90323d3bceb9689a1337bc689d68d93d2..578e4fee2ee156c7f779e84387af37f523192b7f 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts @@ -20,6 +20,7 @@ export class ChartStruct { addr: string = ''; size: number = 0; count: number = 0; + eventCount: number = 0; dur: number = 0; parent: ChartStruct | undefined; children: Array = []; diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts index 3b7fdc78a39121e9b846a0ef74783ef6309dd987..179ac9ef703f3dc0dcda3fed41b901fa4d1ef94b 100644 --- a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -186,13 +186,20 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { let processes = selectionParam.perfAll ? [] : selectionParam.perfProcess; let threads = selectionParam.perfAll ? [] : selectionParam.perfThread; let sql = ''; + let arg4 = ''; if (cpus.length != 0 || processes.length != 0 || threads.length != 0) { let arg1 = cpus.length > 0 ? `or s.cpu_id in (${cpus.join(',')}) ` : ''; let arg2 = processes.length > 0 ? `or thread.process_id in (${processes.join(',')}) ` : ''; let arg3 = threads.length > 0 ? `or s.thread_id in (${threads.join(',')})` : ''; let arg = `${arg1}${arg2}${arg3}`.substring(3); sql = ` and (${arg})`; + let eventTypeId = selectionParam.eventTypeId; + arg4 = eventTypeId ? `and s.event_type_id = ${eventTypeId}` : ''; } + console.log(sql+ ':sql') + console.log(arg4+ ':arg4') + console.log(selectionParam.leftNs + ': selectionParam.leftNs') + console.log(selectionParam.rightNs + ': selectionParam.rightNs') this.queryData( this.currentEventId, 'perf-queryCallchainsGroupSample', @@ -203,8 +210,9 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { p.count, p.process_id as pid, p.event_count as eventCount, - p.ts as ts - from (select callchain_id, s.thread_id, thread_state, process_id, + p.ts as ts, + p.event_type_id as eventTypeId + from (select callchain_id, s.thread_id, s.event_type_id, thread_state, process_id, count(callchain_id) as count,event_count, group_concat(s.timestamp_trace - t.start_ts,',') as ts from perf_sample s, trace_range t @@ -213,7 +221,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { where timestamp_trace between $startTime + t.start_ts and $endTime + t.start_ts and callchain_id != -1 - and s.thread_id != 0 ${sql} + and s.thread_id != 0 ${arg4} ${sql} group by callchain_id, s.thread_id, thread_state, process_id) p`, { $startTime: selectionParam.leftNs, @@ -376,6 +384,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { perfProcessMerageData.initChildren.push(merageData); perfProcessMerageData.dur = merageData.dur; perfProcessMerageData.count = merageData.dur; + perfProcessMerageData.eventCount = merageData.eventCount; perfProcessMerageData.total = totalSamplesCount; perfProcessMerageData.tsArray = [...merageData.tsArray]; rootMerageMap[merageData.pid] = perfProcessMerageData; @@ -384,6 +393,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { rootMerageMap[merageData.pid].initChildren.push(merageData); rootMerageMap[merageData.pid].dur += merageData.dur; rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].eventCount += merageData.eventCount; rootMerageMap[merageData.pid].total = totalSamplesCount; for (const ts of merageData.tsArray) { rootMerageMap[merageData.pid].tsArray.push(ts); @@ -471,6 +481,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { processMerageData.initChildren.push(merageData); processMerageData.dur = merageData.dur; processMerageData.count = merageData.dur; + processMerageData.eventCount = merageData.dur; processMerageData.total = sampleIds.length; rootMerageMap[merageData.pid] = processMerageData; } else { @@ -478,6 +489,7 @@ export class ProcedureLogicWorkerPerf extends LogicHandler { rootMerageMap[merageData.pid].initChildren.push(merageData); rootMerageMap[merageData.pid].dur += merageData.dur; rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].eventCount += merageData.dur; rootMerageMap[merageData.pid].total = sampleIds.length; } merageData.parentNode = rootMerageMap[merageData.pid]; //子节点添加父节点的引用 @@ -971,6 +983,7 @@ export class PerfCallChain { symbolId: number = 0; path: string = ''; count: number = 0; + eventCount: number = 0; parentId: string = ''; //合并之后区分的id id: string = ''; topDownMerageId: string = ''; //top down合并使用的id @@ -999,6 +1012,7 @@ export class PerfCallChain { currentNode.sampleId = callChain.sampleId; currentNode.dur = callChain.dur; currentNode.count = callChain.count; + currentNode.eventCount = callChain.eventCount; } } @@ -1068,6 +1082,7 @@ export class PerfCallChainMerageData extends ChartStruct { } currentNode.dur += callChain.count; currentNode.count += callChain.count; + currentNode.eventCount += callChain.eventCount; } static merageCallChainSample( @@ -1096,6 +1111,7 @@ export class PerfCallChainMerageData extends ChartStruct { } currentNode.dur += sample.count; currentNode.count += sample.count; + currentNode.eventCount += sample.eventCount; currentNode.tsArray.push(...sample.ts.split(',').map(Number)); } }