diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts index b4f2d2530e548e5bc5d154ed863de718ce0e32c6..f21e014e827b27bfaea286be22174801c1522e13 100644 --- a/ide/src/trace/component/chart/SpProcessChart.ts +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -79,6 +79,20 @@ export class SpProcessChart { this.processAsyncFuncMap = Utils.groupBy(asyncFuncList, 'pid'); }; + /** + * 更新无end方法的持续时间 + * @param it 被更新的方法 + * @param i 索引位置 + * @param arr 被更新的方法集合 + */ + modifyNofinishDur(it: FuncStruct, i: number, arr: Array): void { + if (it.dur === -1) { + it.dur = TraceRow.range!.endNS - it.startTs!; + it.flag = 'Did not end'; + it.nofinish = true; + } + } + initDeliverInputEvent = async (): Promise => { let row = TraceRow.skeleton(); row.setAttribute('disabled-check', ''); @@ -114,11 +128,9 @@ export class SpProcessChart { createDepth(++currentDepth, index); } }; - asyncFuncGroups.forEach((it, i) => { - if (it.dur == -1) { - it.dur = (TraceRow.range?.endNS || 0) - it.startTs; - it.flag = 'Did not end'; - } + asyncFuncGroups.forEach((it, i, arr) => { + this.modifyNofinishDur(it, i, arr); + createDepth(0, i); }); let max = Math.max(...asyncFuncGroups.map((it) => it.depth || 0)) + 1; @@ -592,11 +604,9 @@ export class SpProcessChart { let isIntersect = (a: any, b: any): boolean => Math.max(a.startTs + a.dur, b.startTs + b.dur) - Math.min(a.startTs, b.startTs) < a.dur + b.dur; let depthArray: any = []; - asyncFunctions.forEach((it, i) => { - if (it.dur === -1) { - it.dur = (TraceRow.range?.endNS || 0) - it.startTs; - it.flag = 'Did not end'; - } + asyncFunctions.forEach((it, i, arr) => { + this.modifyNofinishDur(it, i, arr); + let currentDepth = 0; let index = i; while ( @@ -797,13 +807,11 @@ export class SpProcessChart { data.funName.toLowerCase().startsWith('binder reply')) ); }; - funs.forEach((fun) => { + funs.forEach((fun, i, arr) => { if (isBinder(fun)) { } else { - if (fun.dur === -1) { - fun.dur = (TraceRow.range?.totalNS || 0) - (fun.startTs || 0); - fun.flag = 'Did not end'; - } + this.modifyNofinishDur(fun, i, arr); + } }); } else { diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts b/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts index 06a433cf84deb32d77b5b0c0e87ac3cd56bd5eb3..fb72dad19841159deaf4a8e7886f09c757e869bf 100644 --- a/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts +++ b/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts @@ -49,20 +49,31 @@ export class TabPaneThreadStates extends BaseElement { async initThreadStates(threadStatesParam: SelectionParam | any) { let leftStartNs = threadStatesParam.leftNs + threadStatesParam.recordStartNs; let rightEndNs = threadStatesParam.rightNs + threadStatesParam.recordStartNs; - - let threadStates = await getTabThreadStates( - threadStatesParam.threadIds, - threadStatesParam.leftNs, - threadStatesParam.rightNs - ); - let threadStatesDetail = await getTabThreadStatesDetail( - threadStatesParam.threadIds, - threadStatesParam.leftNs, - threadStatesParam.rightNs - ); - - let targetListTemp = this.updateThreadStates(threadStates, threadStatesDetail, leftStartNs, rightEndNs); - + let tidSet = new Set(threadStatesParam.threadIds); + let targetListTemp: Array = []; + for (let tid of tidSet) { + let threadStates = await getTabThreadStates( + tid, + threadStatesParam.leftNs, + threadStatesParam.rightNs + ); + let set = new Set(); + for (let threadState of threadStates) { + set.add(threadState.pid + ":" + threadState.tid); + } + for (let item of set) { + let pid = Number.parseInt(item.split(":")[0]); + let tid = Number.parseInt(item.split(":")[1]); + let threadStatesDetail = await getTabThreadStatesDetail(pid, tid, + threadStatesParam.leftNs, + threadStatesParam.rightNs + ); + if (threadStates.length > 0 && threadStatesDetail.length > 0) { + threadStates = this.updateThreadStates(threadStates, threadStatesDetail, leftStartNs, rightEndNs); + } + } + targetListTemp = targetListTemp.concat(threadStates); + } let compare = function (threadState1: SelectionData, threadState2: SelectionData) { let wallDuration1 = threadState1.wallDuration; let wallDuration2 = threadState2.wallDuration; @@ -75,62 +86,80 @@ export class TabPaneThreadStates extends BaseElement { } }; targetListTemp.sort(compare); - this.addSumLine(threadStatesParam, targetListTemp); } + updateOnlyNofinishState(threadState: any, rightEndNs: number, leftStartNs: number): Array { + threadState.wallDuration = threadState.wallDuration + 1 + (rightEndNs - leftStartNs); + threadState.avgDuration = threadState.wallDuration / threadState.occurrences; + return threadState; + } + + updateNormalState(threadStates: Array, threadStatesDetail: Array, + rightEndNs: number, leftStartNs: number): Array { + let targetListTemp: Array = []; + let firstState = threadStatesDetail[0]; + let lastState = threadStatesDetail[threadStatesDetail.length - 1]; + for (let e of threadStates) { + if ( + firstState.ts < leftStartNs && + e.pid === firstState.pid && + e.tid === firstState.tid && + e.state === firstState.state + ) { + e.wallDuration = e.wallDuration - (leftStartNs - firstState.ts); + e.avgDuration = e.wallDuration / e.occurrences; + } + if ( + lastState.ts < rightEndNs && + e.pid === lastState.pid && + e.tid === lastState.tid && + e.state === lastState.state + ) { + if (lastState.dur === -1) { + e.wallDuration = e.wallDuration + 1 + (rightEndNs - lastState.ts); + e.avgDuration = e.wallDuration / e.occurrences; + } else { + e.wallDuration = e.wallDuration - (lastState.ts + lastState.dur - rightEndNs); + e.avgDuration = e.wallDuration / e.occurrences; + } + } + targetListTemp.push(e); + } + return targetListTemp; + } + updateThreadStates( threadStates: Array, threadStatesDetail: Array, leftStartNs: number, rightEndNs: number ): Array { - let targetListTemp = []; - if (threadStates.length > 0 && threadStatesDetail.length > 0) { - let firstState = threadStatesDetail[0]; - let lastState = threadStatesDetail[threadStatesDetail.length - 1]; - for (let e of threadStates) { - if ( - firstState.ts < leftStartNs && - e.process == firstState.process && - e.thread == firstState.thread && - e.state == firstState.state - ) { - e.wallDuration = e.wallDuration - (leftStartNs - firstState.ts); - e.avgDuration = e.wallDuration / e.occurrences; - } - - if ( - lastState.ts < rightEndNs && - e.process == lastState.process && - e.thread == lastState.thread && - e.state == lastState.state - ) { - e.wallDuration = e.wallDuration - (lastState.ts + lastState.dur - rightEndNs); - e.avgDuration = e.wallDuration / e.occurrences; - } - targetListTemp.push(e); + let targetListTemp: Array = []; + if (threadStates.length === 1) { + let threadState = threadStates[0]; + if (threadState.wallDuration === -1) { + targetListTemp = this.updateOnlyNofinishState(threadStates, rightEndNs, leftStartNs); + } else { + targetListTemp = this.updateNormalState(threadStates, threadStatesDetail, rightEndNs, leftStartNs); } + } else { + targetListTemp = this.updateNormalState(threadStates, threadStatesDetail, rightEndNs, leftStartNs); } return targetListTemp; } addSumLine(threadStatesParam: SelectionParam | any, targetListTemp: Array): void { - log(targetListTemp); - - if (targetListTemp != null && targetListTemp.length > 0) { - log('getTabThreadStates result size : ' + targetListTemp.length); + if (targetListTemp != null && targetListTemp.length > 0) { let sumWall = 0.0; let sumOcc = 0; - let targetList = []; - + let targetList: Array = []; for (let e of targetListTemp) { if (threadStatesParam.processIds.includes(e.pid)) { let process = Utils.PROCESS_MAP.get(e.pid); let thread = Utils.THREAD_MAP.get(e.tid); - e.process = process == null || process.length == 0 ? '[NULL]' : process; - e.thread = thread == null || thread.length == 0 ? '[NULL]' : thread; - + e.process = process == null || process.length === 0 ? '[NULL]' : process; + e.thread = thread == null || thread.length === 0 ? '[NULL]' : thread; e.stateJX = e.state; e.state = Utils.getEndState(e.stateJX); e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); diff --git a/ide/src/trace/database/SqlLite.ts b/ide/src/trace/database/SqlLite.ts index 5eb83d890ad2e8169ad581ab1d93dcc5fd8e60be..fb613fb842443a63716120a05ef9e7838cf763ac 100644 --- a/ide/src/trace/database/SqlLite.ts +++ b/ide/src/trace/database/SqlLite.ts @@ -968,7 +968,7 @@ export const getTabSlicesAsyncFunc = ( { $leftNS: leftNS, $rightNS: rightNS } ); -export const getTabThreadStates = (tIds: Array, leftNS: number, rightNS: number): Promise> => +export const getTabThreadStates = (tid: number, leftNS: number, rightNS: number): Promise> => query( 'getTabThreadStates', ` @@ -983,19 +983,19 @@ export const getTabThreadStates = (tIds: Array, leftNS: number, rightNS: thread_state AS B left join trace_range AS TR - where - B.tid in (${tIds.join(',')}) - and - not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) - group by - B.pid, B.tid, B.state - order by - wallDuration desc;`, + where + B.tid = ${tid} + and + not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + group by + B.pid, B.tid, B.state + order by + wallDuration desc;`, { $leftNS: leftNS, $rightNS: rightNS } ); // 查询线程状态详细信息 -export const getTabThreadStatesDetail = (tIds: Array, leftNS: number, rightNS: number): Promise> => +export const getTabThreadStatesDetail = (pid: number, tid: number, leftNS: number, rightNS: number): Promise> => query( 'getTabThreadStates', `select @@ -1008,11 +1008,13 @@ export const getTabThreadStatesDetail = (tIds: Array, leftNS: number, ri thread_state AS B left join trace_range AS TR - where - B.tid in (${tIds.join(',')}) - and - not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) - order by ts;`, + where + B.pid = ${pid} + and + B.tid = ${tid} + and + not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + order by ts;`, { $leftNS: leftNS, $rightNS: rightNS } ); diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts index 0c45cf9d5444db77cb28b87047b9a8ea6c16bda2..9180c68dd9cc24da1cef7b11fcc9a720c7fa4b04 100644 --- a/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts @@ -127,6 +127,7 @@ export class FuncStruct extends BaseFuncStruct { static selectFuncStruct: FuncStruct | undefined; flag: string | undefined; // 570000 textMetricsWidth: number | undefined; + nofinish: boolean = false; static setFuncFrame(funcNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { let x1: number, x2: number; @@ -193,10 +194,39 @@ export class FuncStruct extends BaseFuncStruct { if (flagConfig!.TaskPool === 'Enabled' && data.funName!.indexOf('H:Thread Timeout Exit') >= 0) { FuncStruct.drawTaskPoolTimeOutFlag(ctx, data.frame!.x, (data.depth! + 0.5) * 20, 10, data!); } + let width = data.frame.width || 0; + // 如果该函数没有结束时间,则绘制锯齿。 + if (data.nofinish && width > 4) { + FuncStruct.drawRupture(ctx, data.frame.x, data.frame.y , data.frame.width, data.frame.height ); + } } } } + /** + * 绘制锯齿 + * @param ctx 绘图上下文环境 + * @param x 水平坐标 + * @param y 垂直坐标 + * @param width 函数矩形框的宽度 + * @param height 函数矩形框的高度 + */ + static drawRupture(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) { + ctx.fillStyle = '#fff'; // 白色 + let ruptureWidth = 5; + let ruptureNode = height / ruptureWidth; + let len = height / ruptureNode; + ctx.moveTo(x + width - 1, y); + for (let i = 1; i <= ruptureNode; i++) { + ctx.lineTo( + x + width - 1 - (i % 2 == 0 ? 0 : ruptureWidth), + y + len * i - 2 + ); + } + ctx.closePath(); + ctx.fill(); + } + static drawTaskPoolUnSuccessFlag( ctx: CanvasRenderingContext2D, x: number,