1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { SpSystemTrace } from '../SpSystemTrace'; 17import { Utils } from '../trace/base/Utils'; 18import { info } from '../../../log/Log'; 19import { TraceRow } from '../trace/base/TraceRow'; 20import { ProcessRender, ProcessStruct } from '../../database/ui-worker/ProcedureWorkerProcess'; 21import { ThreadRender, ThreadStruct } from '../../database/ui-worker/ProcedureWorkerThread'; 22import { FuncRender, FuncStruct } from '../../database/ui-worker/ProcedureWorkerFunc'; 23import { MemRender, ProcessMemStruct } from '../../database/ui-worker/ProcedureWorkerMem'; 24import { folderSupplier, folderThreadHandler, getRowContext, rowThreadHandler, SpChartManager } from './SpChartManager'; 25import { JankRender, JankStruct } from '../../database/ui-worker/ProcedureWorkerJank'; 26import { isFrameContainPoint, ns2xByTimeShaft, PairPoint } from '../../database/ui-worker/ProcedureWorkerCommon'; 27import { AppStartupRender, AppStartupStruct } from '../../database/ui-worker/ProcedureWorkerAppStartup'; 28import { SoRender, SoStruct } from '../../database/ui-worker/ProcedureWorkerSoInit'; 29import { FlagsConfig } from '../SpFlags'; 30import { processDataSender } from '../../database/data-trafic/process/ProcessDataSender'; 31import { threadDataSender } from '../../database/data-trafic/process/ThreadDataSender'; 32import { funcDataSender } from '../../database/data-trafic/process/FuncDataSender'; 33import { processMemDataSender } from '../../database/data-trafic/process/ProcessMemDataSender'; 34import { processStartupDataSender } from '../../database/data-trafic/process/ProcessStartupDataSender'; 35import { processSoInitDataSender } from '../../database/data-trafic/process/ProcessSoInitDataSender'; 36import { processExpectedDataSender } from '../../database/data-trafic/process/ProcessExpectedDataSender'; 37import { processActualDataSender } from '../../database/data-trafic/process/ProcessActualDataSender'; 38import { processDeliverInputEventDataSender } from '../../database/data-trafic/process/ProcessDeliverInputEventDataSender'; 39import { getMaxDepthByTid, queryAllFuncNames, queryProcessAsyncFunc } from '../../database/sql/Func.sql'; 40import { queryMemFilterIdMaxValue } from '../../database/sql/Memory.sql'; 41import { queryAllSoInitNames, queryAllSrcSlices, queryEventCountMap } from '../../database/sql/SqlLite.sql'; 42import { 43 queryProcess, 44 queryProcessByTable, 45 queryProcessContentCount, 46 queryProcessMem, 47 queryProcessSoMaxDepth, 48 queryProcessThreads, 49 queryProcessThreadsByTable, 50 queryStartupPidArray, 51 queryRsProcess, 52 queryTaskPoolProcessIds, 53} from '../../database/sql/ProcessThread.sql'; 54import { queryAllJankProcess } from '../../database/sql/Janks.sql'; 55import { BaseStruct } from '../../bean/BaseStruct'; 56 57export class SpProcessChart { 58 private readonly trace: SpSystemTrace; 59 private processAsyncFuncMap: unknown = {}; 60 private processAsyncFuncArray: unknown[] = []; 61 private eventCountMap: unknown; 62 private processThreads: Array<ThreadStruct> = []; 63 private processMem: Array<unknown> = []; 64 private processThreadCountMap: Map<number, number> = new Map(); 65 private processThreadDataCountMap: Map<number, number> = new Map(); 66 private processFuncDataCountMap: Map<number, number> = new Map(); 67 private processMemDataCountMap: Map<number, number> = new Map(); 68 private threadFuncMaxDepthMap: Map<string, number> = new Map(); 69 private startupProcessArr: { pid: number }[] = []; 70 private processSoMaxDepth: { pid: number; maxDepth: number }[] = []; 71 private funcNameMap: Map<number, string> = new Map(); 72 private filterIdMaxValue: Map<number, number> = new Map(); 73 private soInitNameMap: Map<number, string> = new Map(); 74 private processSrcSliceMap: Map<number, string> = new Map(); 75 private renderRow: TraceRow<BaseStruct> | null = null; 76 private loadAppStartup: boolean = false; 77 constructor(trace: SpSystemTrace) { 78 this.trace = trace; 79 } 80 81 initAsyncFuncData = async (traceRange: { startTs: number; endTs: number }): Promise<void> => { 82 const funcNamesArray = await queryAllFuncNames(); 83 funcNamesArray.forEach((it) => { 84 //@ts-ignore 85 this.funcNameMap.set(it.id, it.name); 86 }); 87 let asyncFuncList: unknown[] = await queryProcessAsyncFunc(traceRange); 88 for (const func of asyncFuncList) { 89 //@ts-ignore 90 func.funName = this.funcNameMap.get(func.id); //@ts-ignore 91 func.threadName = Utils.THREAD_MAP.get(func.tid); 92 } 93 info('AsyncFuncData Count is: ', asyncFuncList!.length); 94 this.processAsyncFuncArray = asyncFuncList; 95 this.processAsyncFuncMap = Utils.groupBy(asyncFuncList, 'pid'); 96 }; 97 98 initDeliverInputEvent = async (): Promise<void> => { 99 let row = TraceRow.skeleton(); 100 row.setAttribute('disabled-check', ''); 101 row.rowId = 'DeliverInputEvent'; 102 row.index = 0; 103 row.rowType = TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT; 104 row.rowParentId = ''; 105 row.folder = true; 106 row.style.height = '40px'; 107 row.name = 'DeliverInputEvent'; 108 // @ts-ignore 109 row.supplier = folderSupplier(); 110 row.onThreadHandler = folderThreadHandler(row, this.trace); 111 112 let asyncFuncGroup = Utils.groupBy( 113 //@ts-ignore 114 this.processAsyncFuncArray.filter((it) => it.funName === 'deliverInputEvent'), 115 'tid' 116 ); // @ts-ignore 117 if (Reflect.ownKeys(asyncFuncGroup).length > 0) { 118 this.trace.rowsEL?.appendChild(row); 119 } // @ts-ignore 120 Reflect.ownKeys(asyncFuncGroup).map((key: unknown) => { 121 // @ts-ignore 122 let asyncFuncGroups: Array<unknown> = asyncFuncGroup[key]; 123 if (asyncFuncGroups.length > 0) { 124 //@ts-ignore 125 row.addChildTraceRow(this.createDeliverInputEventRow(row, key, asyncFuncGroups)); 126 } 127 }); 128 }; 129 130 private createDeliverInputEventRow( 131 //@ts-ignore 132 parentRow: TraceRow<unknown>, 133 key: number, 134 asyncFuncGroups: Array<unknown> 135 ): TraceRow<FuncStruct> { 136 let funcRow = TraceRow.skeleton<FuncStruct>(); //@ts-ignore 137 funcRow.rowId = `${asyncFuncGroups[0].funName}-${key}`; //@ts-ignore 138 funcRow.asyncFuncName = asyncFuncGroups[0].funName; 139 funcRow.asyncFuncNamePID = key; 140 funcRow.rowType = TraceRow.ROW_TYPE_FUNC; 141 funcRow.enableCollapseChart(); //允许折叠泳道图 142 funcRow.rowParentId = `${parentRow.rowId}`; 143 funcRow.rowHidden = !parentRow.expansion; 144 funcRow.style.width = '100%'; //@ts-ignore 145 funcRow.name = `${asyncFuncGroups[0].funName} ${key}`; 146 funcRow.setAttribute('children', ''); 147 funcRow.supplierFrame = async (): Promise<FuncStruct[]> => { 148 const res = await processDeliverInputEventDataSender(key, funcRow!); 149 this.deliverInputEventSendCallback(res, funcRow, asyncFuncGroups); 150 return res; 151 }; 152 funcRow.findHoverStruct = (): void => { 153 FuncStruct.hoverFuncStruct = funcRow.getHoverStruct(); 154 }; 155 funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 156 funcRow.selectChangeHandler = this.trace.selectChangeHandler; 157 funcRow.onThreadHandler = rowThreadHandler<FuncRender>( 158 'func', 159 'context', 160 { 161 //@ts-ignore 162 type: `func-${asyncFuncGroups[0].funName}-${key}`, 163 }, 164 funcRow, 165 this.trace 166 ); 167 return funcRow; 168 } 169 //@ts-ignore 170 private deliverInputEventSendCallback( 171 res: Array<unknown>, //@ts-ignore 172 funcRow: TraceRow<unknown>, 173 asyncFuncGroups: Array<unknown> 174 ): void { 175 let isIntersect = ( 176 left: unknown, 177 right: unknown 178 ): boolean => //@ts-ignore 179 Math.max(left.startTs + left.dur, right.startTs + right.dur) - Math.min(left.startTs, right.startTs) < //@ts-ignore 180 left.dur + right.dur; 181 let depths: unknown = []; 182 let createDepth = (currentDepth: number, index: number): void => { 183 //@ts-ignore 184 if (depths[currentDepth] === undefined || !isIntersect(depths[currentDepth], res[index])) { 185 //@ts-ignore 186 res[index].depth = currentDepth; //@ts-ignore 187 depths[currentDepth] = res[index]; 188 } else { 189 createDepth(++currentDepth, index); 190 } 191 }; 192 res.forEach((it, i): void => { 193 //@ts-ignore 194 res[i].funName = this.funcNameMap.get(res[i].id!); //@ts-ignore 195 res[i].threadName = Utils.THREAD_MAP.get(res[i].tid!); //@ts-ignore 196 if (it.dur === -1 || it.dur === null || it.dur === undefined) { 197 //@ts-ignore 198 it.dur = (TraceRow.range?.endNS || 0) - it.startTs; //@ts-ignore 199 it.flag = 'Did not end'; 200 } 201 createDepth(0, i); 202 }); 203 if (funcRow && !funcRow.isComplete) { 204 //@ts-ignore 205 let max = Math.max(...asyncFuncGroups.map((it) => it.depth || 0)) + 1; 206 let maxHeight = max * 18 + 6; 207 funcRow.style.height = `${maxHeight}px`; 208 funcRow.setAttribute('height', `${maxHeight}`); 209 } 210 } 211 212 async init(): Promise<void> { 213 await this.prepareData(); 214 if ( 215 //@ts-ignore 216 this.eventCountMap.print === 0 && //@ts-ignore 217 this.eventCountMap.tracing_mark_write === 0 && //@ts-ignore 218 this.eventCountMap.sched_switch === 0 219 ) { 220 return; 221 } 222 let time = new Date().getTime(); 223 let processes = await queryProcess(); 224 let processFromTable = await queryProcessByTable(); 225 let processList = Utils.removeDuplicates(processes, processFromTable, 'pid'); 226 let allJankProcessData = await queryAllJankProcess(); 227 let allJankProcess: Array<number> = []; 228 if (allJankProcessData.length > 0) { 229 allJankProcessData.forEach((name, index) => { 230 allJankProcess.push(name.pid!); 231 }); 232 } 233 let allTaskPoolPid: Array<{ pid: number }> = []; 234 if (FlagsConfig.getFlagsConfigEnableStatus('TaskPool')) { 235 allTaskPoolPid = await queryTaskPoolProcessIds(); 236 } 237 let renderServiceProcess = await queryRsProcess(); // @ts-ignore 238 info('ProcessList Data size is: ', processList!.length); // @ts-ignore 239 await this.initProcessRow(processList, allTaskPoolPid, allJankProcess, renderServiceProcess); 240 let durTime = new Date().getTime() - time; 241 info('The time to load the Process data is: ', durTime); 242 } 243 244 private async prepareData(): Promise<void> { 245 let maxValues = await queryMemFilterIdMaxValue(); 246 maxValues.forEach((it) => { 247 this.filterIdMaxValue.set(it.filterId, it.maxValue); 248 }); 249 250 let soInitNamesArray = await queryAllSoInitNames(); 251 soInitNamesArray.forEach((it) => { 252 //@ts-ignore 253 this.soInitNameMap.set(it.id, it.name); 254 }); 255 let processSrcSliceArray = await queryAllSrcSlices(); 256 processSrcSliceArray.forEach((it) => { 257 //@ts-ignore 258 this.processSrcSliceMap.set(it.id, it.src); 259 }); 260 let threadFuncMaxDepthArray = await getMaxDepthByTid(); 261 info('Gets the maximum tier per thread , tid and maxDepth'); 262 threadFuncMaxDepthArray.forEach((it) => { 263 //@ts-ignore 264 this.threadFuncMaxDepthMap.set(`${it.ipid}-${it.tid}`, it.maxDepth); 265 }); 266 info('convert tid and maxDepth array to map'); 267 let pidCountArray = await queryProcessContentCount(); 268 info('fetch per process pid,switch_count,thread_count,slice_count,mem_count'); 269 pidCountArray.forEach((it) => { 270 //@ts-ignore 271 this.processThreadDataCountMap.set(it.pid, it.switch_count); //@ts-ignore 272 this.processThreadCountMap.set(it.pid, it.thread_count); //@ts-ignore 273 this.processFuncDataCountMap.set(it.pid, it.slice_count); //@ts-ignore 274 this.processMemDataCountMap.set(it.pid, it.mem_count); 275 }); 276 this.processMem = await queryProcessMem(); 277 info('The amount of initialized process memory data is : ', this.processMem!.length); 278 this.loadAppStartup = FlagsConfig.getFlagsConfigEnableStatus('AppStartup'); 279 info('Prepare App startup data '); 280 if (this.loadAppStartup) { 281 this.startupProcessArr = await queryStartupPidArray(); 282 this.processSoMaxDepth = await queryProcessSoMaxDepth(); 283 } 284 let eventCountList: Array<unknown> = await queryEventCountMap(); 285 this.eventCountMap = eventCountList.reduce((pre, current) => { 286 //@ts-ignore 287 pre[`${current.eventName}`] = current.count; 288 return pre; 289 }, {}); 290 let queryProcessThreadResult = await queryProcessThreads(); 291 let queryProcessThreadsByTableResult = await queryProcessThreadsByTable(); // @ts-ignore 292 this.processThreads = Utils.removeDuplicates(queryProcessThreadResult, queryProcessThreadsByTableResult, 'tid'); 293 info('The amount of initialized process threads data is : ', this.processThreads!.length); 294 } 295 296 private async initProcessRow( 297 pArr: Array<unknown>, 298 allTaskPoolPid: Array<{ pid: number }>, 299 jankArr: Array<number>, 300 rsProcess: Array<unknown> 301 ): Promise<void> { 302 for (let i = 0; i < pArr.length; i++) { 303 const it = pArr[i]; 304 if ( 305 //@ts-ignore 306 (this.processThreadDataCountMap.get(it.pid) || 0) === 0 && //@ts-ignore 307 (this.processThreadCountMap.get(it.pid) || 0) === 0 && //@ts-ignore 308 (this.processFuncDataCountMap.get(it.pid) || 0) === 0 && //@ts-ignore 309 (this.processMemDataCountMap.get(it.pid) || 0) === 0 310 ) { 311 continue; 312 } 313 let processRow = this.createProcessRow(i, it, allTaskPoolPid); 314 this.trace.rowsEL?.appendChild(processRow); 315 /* App Startup row*/ 316 let startupRow: TraceRow<AppStartupStruct> | undefined = undefined; 317 let soRow: TraceRow<SoStruct> | undefined = undefined; 318 if (this.loadAppStartup) { 319 //@ts-ignore 320 if (this.startupProcessArr.find((sp) => sp.pid === it.pid)) { 321 startupRow = this.addStartUpRow(processRow); 322 } //@ts-ignore 323 let maxSoDepth = this.processSoMaxDepth.find((md) => md.pid === it.pid); 324 if (maxSoDepth) { 325 soRow = this.addSoInitRow(processRow, maxSoDepth.maxDepth); 326 } 327 } 328 329 let actualRow: TraceRow<JankStruct> | null = null; 330 let expectedRow: TraceRow<JankStruct> | null = null; 331 this.renderRow = null; //@ts-ignore 332 if (it.processName === 'render_service') { 333 //@ts-ignore 334 this.addThreadList(it, processRow, expectedRow, actualRow, soRow, startupRow); //@ts-ignore 335 this.addProcessMemInfo(it, processRow); //@ts-ignore 336 if (jankArr.indexOf(it.pid!) > -1) { 337 expectedRow = this.addExpectedRow(it, processRow, rsProcess); 338 actualRow = this.addActualRow(it, processRow, rsProcess); 339 } 340 this.addProcessRowListener(processRow, actualRow); //@ts-ignore 341 this.addAsyncFunction(it, processRow); 342 } else { 343 //@ts-ignore 344 if (jankArr.indexOf(it.pid!) > -1) { 345 expectedRow = this.addExpectedRow(it, processRow, rsProcess); 346 actualRow = this.addActualRow(it, processRow, rsProcess); 347 } 348 this.addProcessRowListener(processRow, actualRow); //@ts-ignore 349 this.addAsyncFunction(it, processRow); //@ts-ignore 350 this.addProcessMemInfo(it, processRow); //@ts-ignore 351 this.addThreadList(it, processRow, expectedRow, actualRow, soRow, startupRow); 352 } 353 354 //@ts-ignore 355 await this.trace.chartManager?.frameTimeChart.initAnimatedScenesChart(processRow, it, expectedRow!, actualRow!); 356 } 357 } 358 359 private createProcessRow( 360 index: number, 361 process: unknown, 362 allTaskPoolPid: Array<{ pid: number }> 363 ): TraceRow<ProcessStruct> { 364 let processRow = TraceRow.skeleton<ProcessStruct>(); //@ts-ignore 365 processRow.rowId = `${process.pid}`; 366 processRow.index = index; 367 processRow.rowType = TraceRow.ROW_TYPE_PROCESS; 368 processRow.rowParentId = ''; 369 processRow.style.height = '40px'; 370 processRow.folder = true; 371 if ( 372 //@ts-ignore 373 SpChartManager.APP_STARTUP_PID_ARR.find((pid) => pid === process.pid) !== undefined || //@ts-ignore 374 process.processName === 'render_service' 375 ) { 376 processRow.addTemplateTypes('AppStartup'); 377 } 378 if (allTaskPoolPid.find((process) => process.pid === process.pid) !== undefined) { 379 processRow.addTemplateTypes('TaskPool'); 380 } //@ts-ignore 381 processRow.name = `${process.processName || 'Process'} ${process.pid}`; //@ts-ignore 382 processRow.supplierFrame = (): Promise<Array<unknown>> => { 383 //@ts-ignore 384 return processDataSender(process.pid || -1, processRow); 385 }; 386 processRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 387 processRow.selectChangeHandler = this.trace.selectChangeHandler; 388 processRow.onThreadHandler = rowThreadHandler<ProcessRender>( 389 'process', 390 'context', 391 { 392 //@ts-ignore 393 pid: process.pid, //@ts-ignore 394 type: `process ${processRow.index} ${process.processName}`, 395 }, 396 processRow, 397 this.trace 398 ); 399 return processRow; 400 } 401 402 addProcessRowListener(processRow: TraceRow<ProcessStruct>, actualRow: TraceRow<JankStruct> | null): void { 403 let offsetYTimeOut: unknown = undefined; 404 processRow.addEventListener('expansion-change', (e: unknown) => { 405 JankStruct.delJankLineFlag = false; 406 if (offsetYTimeOut) { 407 //@ts-ignore 408 clearTimeout(offsetYTimeOut); 409 } 410 if (JankStruct.selectJankStruct !== null && JankStruct.selectJankStruct !== undefined) { 411 //@ts-ignore 412 if (e.detail.expansion) { 413 offsetYTimeOut = setTimeout(() => { 414 this.trace.linkNodes.forEach((linkNodeItem) => this.handler1(e, linkNodeItem, actualRow)); 415 }, 300); 416 } else { 417 if (JankStruct!.selectJankStruct) { 418 JankStruct.selectJankStructList?.push(<JankStruct>JankStruct!.selectJankStruct); 419 } 420 offsetYTimeOut = setTimeout(() => { 421 this.trace.linkNodes?.forEach((linkProcessItem) => this.handler2(e, linkProcessItem, processRow)); 422 }, 300); 423 } 424 } else { 425 //@ts-ignore 426 if (e.detail.expansion) { 427 offsetYTimeOut = setTimeout(() => { 428 this.trace.linkNodes.forEach((linkNodeItem) => this.handler3(e, linkNodeItem)); 429 }, 300); 430 } else { 431 if (ThreadStruct!.selectThreadStruct) { 432 ThreadStruct.selectThreadStructList?.push(<ThreadStruct>ThreadStruct!.selectThreadStruct); 433 } 434 offsetYTimeOut = setTimeout(() => { 435 this.trace.linkNodes?.forEach((linkProcessItem) => { 436 this.handler4(e, linkProcessItem, processRow); 437 JankStruct.selectJankStructList = []; 438 }); 439 }, 300); 440 } 441 } 442 let refreshTimeOut = setTimeout(() => { 443 this.trace.refreshCanvas(true); 444 clearTimeout(refreshTimeOut); 445 }, 360); 446 }); 447 } 448 449 handler1(e: unknown, linkItem: PairPoint[], actualRow: TraceRow<JankStruct> | null): void { 450 JankStruct.selectJankStructList?.forEach((selectProcessStruct: unknown) => { 451 //@ts-ignore 452 if (e.detail.rowId === selectProcessStruct.pid) { 453 //@ts-ignore 454 JankStruct.selectJankStruct = selectProcessStruct; //@ts-ignore 455 JankStruct.hoverJankStruct = selectProcessStruct; 456 } 457 }); 458 this.updatePairPointTranslateY(linkItem[0]); 459 linkItem[0].y = linkItem[0].rowEL!.translateY! + linkItem[0].offsetY; 460 this.updatePairPointTranslateY(linkItem[1]); 461 linkItem[1].y = linkItem[1].rowEL!.translateY! + linkItem[1].offsetY; 462 if (actualRow) { 463 //@ts-ignore 464 if (linkItem[0].rowEL.rowId === e.detail.rowId) { 465 linkItem[0].x = ns2xByTimeShaft(linkItem[0].ns, this.trace.timerShaftEL!); 466 linkItem[0].y = actualRow!.translateY! + linkItem[0].offsetY * 2; 467 linkItem[0].offsetY = linkItem[0].offsetY * 2; 468 //@ts-ignore 469 linkItem[0].rowEL = actualRow!; 470 //@ts-ignore 471 } else if (linkItem[1].rowEL.rowId === e.detail.rowId) { 472 linkItem[1].x = ns2xByTimeShaft(linkItem[1].ns, this.trace.timerShaftEL!); 473 linkItem[1].y = actualRow!.translateY! + linkItem[1].offsetY * 2; 474 linkItem[1].offsetY = linkItem[1].offsetY * 2; 475 //@ts-ignore 476 linkItem[1].rowEL = actualRow!; 477 } 478 } 479 } 480 481 handler2(e: unknown, linkItem: PairPoint[], processRow: TraceRow<ProcessStruct>): void { 482 this.updatePairPointTranslateY(linkItem[0]); 483 linkItem[0].y = linkItem[0].rowEL!.translateY! + linkItem[0].offsetY; 484 this.updatePairPointTranslateY(linkItem[1]); 485 linkItem[1].y = linkItem[1].rowEL!.translateY! + linkItem[1].offsetY; //@ts-ignore 486 if (linkItem[0].rowEL.rowParentId === e.detail.rowId) { 487 this.updatePairPoint(linkItem[0], processRow); //@ts-ignore 488 } else if (linkItem[1].rowEL.rowParentId === e.detail.rowId) { 489 this.updatePairPoint(linkItem[1], processRow); 490 } 491 } 492 493 handler3(e: unknown, linkItem: PairPoint[]): void { 494 ThreadStruct.selectThreadStructList?.forEach((selectProcessStruct: unknown) => { 495 //@ts-ignore 496 if (e.detail.rowId === selectProcessStruct.pid) { 497 //@ts-ignore 498 ThreadStruct.selectThreadStruct = selectProcessStruct; //@ts-ignore 499 ThreadStruct.hoverThreadStruct = selectProcessStruct; 500 } 501 }); 502 if (linkItem[0].rowEL.expansion && linkItem[0].backrowEL) { 503 this.updatePairPointTranslateY(linkItem[0]); 504 linkItem[0].x = ns2xByTimeShaft(linkItem[0].ns, this.trace.timerShaftEL!); 505 linkItem[0].y = linkItem[0].rowEL.translateY + linkItem[0].offsetY; 506 linkItem[0].offsetY = linkItem[0].offsetY * 2; 507 linkItem[0].rowEL = linkItem[0].backrowEL; 508 } 509 if (linkItem[1].rowEL.expansion && linkItem[1].backrowEL) { 510 this.updatePairPointTranslateY(linkItem[1]); 511 linkItem[1].x = ns2xByTimeShaft(linkItem[1].ns, this.trace.timerShaftEL!); 512 linkItem[1].y = linkItem[1].rowEL!.translateY! + linkItem[1].offsetY; 513 linkItem[1].offsetY = linkItem[1].offsetY * 2; 514 linkItem[1].rowEL = linkItem[1].backrowEL; 515 } 516 } 517 518 handler4(e: unknown, linkItem: PairPoint[], processRow: TraceRow<ProcessStruct>): void { 519 this.updatePairPointTranslateY(linkItem[0]); 520 linkItem[0].y = processRow!.translateY + linkItem[0].offsetY; 521 this.updatePairPointTranslateY(linkItem[1]); 522 linkItem[1].y = linkItem[1].rowEL!.translateY + linkItem[1].offsetY; //@ts-ignore 523 if (linkItem[0].rowEL.rowParentId === e.detail.rowId) { 524 //@ts-ignore 525 this.updatePairPoint(linkItem[0], processRow); 526 } //@ts-ignore 527 if (linkItem[1].rowEL.rowParentId === e.detail.rowId) { 528 this.updatePairPoint(linkItem[1], processRow); 529 } 530 } 531 532 updatePairPointTranslateY(pair: PairPoint): void { 533 if (pair.rowEL.collect) { 534 pair.rowEL.translateY = pair.rowEL.getBoundingClientRect().top - 195; 535 } else { 536 pair.rowEL.translateY = pair.rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; 537 } 538 } 539 540 updatePairPoint(pair: PairPoint, processRow: TraceRow<ProcessStruct>): void { 541 if (!pair.rowEL.collect) { 542 pair.x = ns2xByTimeShaft(pair.ns, this.trace.timerShaftEL!); 543 pair.y = processRow!.translateY! + pair.offsetY / 2; 544 pair.offsetY = pair.offsetY / 2; 545 pair.rowEL = processRow!; 546 } 547 } 548 /* Janks Frames */ 549 //@ts-ignore 550 addExpectedRow( 551 process: unknown, //@ts-ignore 552 processRow: TraceRow<unknown>, 553 renderServiceProcess: Array<unknown> 554 ): TraceRow<JankStruct> { 555 let expectedRow = TraceRow.skeleton<JankStruct>(); //@ts-ignore 556 expectedRow.asyncFuncName = process.processName; //@ts-ignore 557 expectedRow.asyncFuncNamePID = process.pid; 558 expectedRow.rowType = TraceRow.ROW_TYPE_JANK; //@ts-ignore 559 expectedRow.rowParentId = `${process.pid}`; 560 expectedRow.rowHidden = !processRow.expansion; 561 expectedRow.style.width = '100%'; 562 expectedRow.name = 'Expected Timeline'; 563 expectedRow.addTemplateTypes('FrameTimeline'); 564 expectedRow.setAttribute('children', ''); 565 expectedRow.supplierFrame = async (): Promise<JankStruct[]> => { 566 //@ts-ignore 567 let res = await processExpectedDataSender(process.pid, expectedRow!); 568 this.jankSenderCallback(res, 'expected', process, expectedRow, renderServiceProcess); 569 return res; 570 }; 571 expectedRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 572 expectedRow.selectChangeHandler = this.trace.selectChangeHandler; 573 expectedRow.onThreadHandler = rowThreadHandler<JankRender>( 574 'jank', 575 'context', 576 { 577 type: 'expected_frame_timeline_slice', 578 }, 579 expectedRow, 580 this.trace 581 ); 582 if (this.renderRow) { 583 processRow.addChildTraceRowBefore(expectedRow, this.renderRow); 584 } else { 585 processRow.addChildTraceRow(expectedRow); 586 } 587 return expectedRow; 588 } 589 590 //@ts-ignore 591 addActualRow( 592 process: unknown, //@ts-ignore 593 processRow: TraceRow<unknown>, 594 renderServiceProcess: Array<unknown> 595 ): TraceRow<JankStruct> { 596 let actualRow = TraceRow.skeleton<JankStruct>(); 597 actualRow.rowType = TraceRow.ROW_TYPE_JANK; //@ts-ignore 598 actualRow.rowParentId = `${process.pid}`; 599 actualRow.rowHidden = !processRow.expansion; 600 actualRow.style.width = '100%'; 601 actualRow.name = 'Actual Timeline'; 602 actualRow.addTemplateTypes('FrameTimeline'); 603 actualRow.setAttribute('children', ''); 604 actualRow.supplierFrame = async (): Promise<JankStruct[]> => { 605 //@ts-ignore 606 let res = await processActualDataSender(process.pid, actualRow!); 607 this.jankSenderCallback(res, 'actual', process, actualRow, renderServiceProcess); 608 return res; 609 }; 610 actualRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 611 actualRow.selectChangeHandler = this.trace.selectChangeHandler; 612 actualRow.onThreadHandler = rowThreadHandler<JankRender>( 613 'jank', 614 'context', 615 { 616 type: 'actual_frame_timeline_slice', 617 }, 618 actualRow, 619 this.trace 620 ); 621 if (this.renderRow) { 622 processRow.addChildTraceRowBefore(actualRow, this.renderRow); 623 } else { 624 processRow.addChildTraceRow(actualRow); 625 } 626 return actualRow; 627 } 628 629 jankSenderCallback( 630 res: JankStruct[], 631 type: string, 632 process: unknown, 633 row: TraceRow<JankStruct>, 634 renderServiceProcess: Array<unknown> 635 ): void { 636 let maxDepth: number = 1; 637 let unitHeight: number = 20; 638 for (let j = 0; j < res.length; j++) { 639 let struct = res[j]; 640 if (struct.depth! >= maxDepth) { 641 maxDepth = struct.depth! + 1; 642 } 643 if (type === 'actual') { 644 struct.src_slice = this.processSrcSliceMap.get(res[j].id!); 645 } 646 struct.cmdline = Utils.PROCESS_MAP.get(res[j].pid!); //@ts-ignore 647 if (res[j].pid! === renderServiceProcess[0].pid) { 648 struct.cmdline = 'render_service'; 649 struct.frame_type = struct.cmdline; 650 } else { 651 struct.frame_type = 'app'; 652 } 653 } 654 if (row && !row.isComplete && res.length > 0) { 655 let maxHeight: number = maxDepth * unitHeight; 656 row.style.height = `${maxHeight}px`; 657 row.setAttribute('height', `${maxHeight}`); 658 if (res[0]) { 659 let timeLineType = res[0].type; //@ts-ignore 660 row.rowId = `${timeLineType}-${process.pid}`; 661 row.setAttribute('frame_type', res[0].frame_type || ''); 662 if (type === 'actual') { 663 row.dataList = res; 664 } 665 } 666 } 667 } 668 669 addStartUpRow(processRow: TraceRow<ProcessStruct>): TraceRow<AppStartupStruct> { 670 processRow.setAttribute('hasStartup', 'true'); 671 let startupRow: TraceRow<AppStartupStruct> = TraceRow.skeleton<AppStartupStruct>(); 672 startupRow.rowId = `app-start-${processRow.rowId}`; 673 startupRow.rowType = TraceRow.ROW_TYPE_APP_STARTUP; 674 startupRow.rowParentId = `${processRow.rowId}`; 675 startupRow.rowHidden = !processRow.expansion; 676 startupRow.index = 0; 677 startupRow.style.height = '30px'; 678 startupRow.style.width = '100%'; 679 startupRow.name = 'App Startups'; 680 startupRow.findHoverStruct = (): void => { 681 AppStartupStruct.hoverStartupStruct = startupRow.getHoverStruct(); 682 }; 683 startupRow.setAttribute('children', ''); 684 startupRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 685 startupRow.selectChangeHandler = this.trace.selectChangeHandler; 686 startupRow.supplierFrame = (): Promise<Array<AppStartupStruct>> => 687 processStartupDataSender(parseInt(processRow.rowId!), startupRow).then((res) => { 688 if (res.length <= 0) { 689 this.trace.refreshCanvas(true); 690 } 691 for (let i = 0; i < res.length; i++) { 692 if (res[i].startName! < 6 && i < res.length - 1) { 693 res[i].endItid = res[i + 1].itid; 694 } 695 } 696 return res; 697 }); 698 startupRow.onThreadHandler = rowThreadHandler<AppStartupRender>( 699 'app-start-up', 700 'appStartupContext', 701 { 702 type: `app-startup ${processRow.rowId}`, 703 }, 704 startupRow, 705 this.trace 706 ); 707 processRow.addChildTraceRow(startupRow); 708 return startupRow; 709 } 710 711 addSoInitRow(processRow: TraceRow<ProcessStruct>, maxDepth: number): TraceRow<SoStruct> { 712 processRow.setAttribute('hasStaticInit', 'true'); 713 let maxHeight = (maxDepth + 1) * 20; 714 let soRow: TraceRow<SoStruct> = TraceRow.skeleton<SoStruct>(); 715 soRow.rowId = `app-start-${processRow.rowId}`; 716 soRow.rowType = TraceRow.ROW_TYPE_STATIC_INIT; 717 soRow.rowParentId = `${processRow.rowId}`; 718 soRow.rowHidden = !processRow.expansion; 719 soRow.index = 0; 720 soRow.style.height = `${maxHeight}px`; 721 soRow.style.width = '100%'; 722 soRow.name = 'Static Initialization'; 723 soRow.setAttribute('children', ''); 724 soRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 725 soRow.selectChangeHandler = this.trace.selectChangeHandler; 726 soRow.findHoverStruct = (): void => { 727 SoStruct.hoverSoStruct = soRow.getHoverStruct(); 728 }; 729 soRow.supplierFrame = (): Promise<Array<SoStruct>> => 730 processSoInitDataSender(parseInt(processRow.rowId!), soRow).then((res) => { 731 if (res.length <= 0) { 732 this.trace.refreshCanvas(true); 733 } 734 res.forEach((so, index) => { 735 let soName = this.soInitNameMap.get(res[index].id!); 736 if (soName) { 737 so.soName = soName.replace('dlopen: ', ''); 738 } 739 }); 740 return res; 741 }); 742 soRow.onThreadHandler = rowThreadHandler<SoRender>( 743 'app-so-init', 744 'context', 745 { 746 type: `static-init ${processRow.rowId}`, 747 }, 748 soRow, 749 this.trace 750 ); 751 processRow.addChildTraceRow(soRow); 752 return soRow; 753 } 754 755 insertAfter(newEl: HTMLElement, targetEl: HTMLElement): void { 756 let parentEl = targetEl.parentNode; 757 if (parentEl!.lastChild === targetEl) { 758 parentEl!.appendChild(newEl); 759 } else { 760 parentEl!.insertBefore(newEl, targetEl.nextSibling); 761 } 762 } 763 764 //add thread list 765 addThreadList( 766 it: { pid: number | null; processName: string | null }, 767 pRow: TraceRow<ProcessStruct>, 768 expectedRow: TraceRow<JankStruct> | null, 769 actualRow: TraceRow<JankStruct> | null, 770 soRow: TraceRow<SoStruct> | undefined, 771 startupRow: TraceRow<AppStartupStruct> | undefined 772 ): void { 773 let threads = this.processThreads.filter((thread) => thread.pid === it.pid && thread.tid !== 0); 774 let tRowArr: Array<TraceRow<BaseStruct>> = []; 775 for (let j = 0; j < threads.length; j++) { 776 let thread = threads[j]; 777 let tRow = TraceRow.skeleton<ThreadStruct>(); 778 tRow.rowId = `${thread.tid}`; 779 tRow.rowType = TraceRow.ROW_TYPE_THREAD; 780 tRow.rowParentId = `${it.pid}`; 781 tRow.rowHidden = !pRow.expansion; 782 tRow.index = j; 783 tRow.style.height = '18px'; 784 tRow.style.width = '100%'; 785 tRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`; 786 tRow.namePrefix = `${thread.threadName || 'Thread'}`; 787 tRow.setAttribute('children', ''); 788 tRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 789 tRow.selectChangeHandler = this.trace.selectChangeHandler; 790 tRow.findHoverStruct = (): void => this.threadRowFindHoverStruct(tRow); 791 tRow.supplierFrame = async (): Promise<Array<ThreadStruct>> => { 792 const res = await threadDataSender(thread.tid || 0, it.pid || 0, tRow); 793 if (res === true) { 794 return []; 795 } else { 796 let rs = res as ThreadStruct[]; 797 if (rs.length <= 0 && !tRow.isComplete) { 798 this.trace.refreshCanvas(true); 799 } 800 return rs; 801 } 802 }; 803 tRow.onThreadHandler = rowThreadHandler<ThreadRender>( 804 'thread', 805 'context', 806 { 807 type: `thread ${thread.tid} ${thread.threadName}`, 808 translateY: tRow.translateY, 809 }, 810 tRow, 811 this.trace 812 ); 813 this.insertRowToDoc(it, j, thread, pRow, tRow, threads, tRowArr, actualRow, expectedRow, startupRow, soRow); 814 this.addFuncStackRow(it, thread, j, threads, tRowArr, tRow, pRow); 815 if ((thread.switchCount || 0) === 0) { 816 tRow.rowDiscard = true; 817 } 818 } 819 } 820 821 threadRowFindHoverStruct(threadRow: TraceRow<ThreadStruct>): void { 822 let arr = threadRow.dataListCache.filter( 823 (re) => re.frame && isFrameContainPoint(re.frame, threadRow.hoverX, threadRow.hoverY, true, false) 824 ); 825 let runItem = arr.find((it) => it.state === 'Running'); 826 if (runItem) { 827 ThreadStruct.hoverThreadStruct = runItem; 828 } else { 829 let otherItem = arr.find((it) => it.state !== 'S'); 830 if (otherItem) { 831 ThreadStruct.hoverThreadStruct = otherItem; 832 } else { 833 ThreadStruct.hoverThreadStruct = arr[0]; 834 } 835 } 836 } 837 838 insertRowToDoc( 839 it: unknown, 840 index: number, 841 thread: ThreadStruct, 842 processRow: TraceRow<ProcessStruct>, 843 threadRow: TraceRow<ThreadStruct>, 844 threads: ThreadStruct[], //@ts-ignore 845 threadRowArr: TraceRow<unknown>[], //@ts-ignore 846 actualRow: TraceRow<unknown> | null, //@ts-ignore 847 expectedRow: TraceRow<unknown> | null, 848 startupRow: TraceRow<AppStartupStruct> | null | undefined, 849 soRow: TraceRow<SoStruct> | null | undefined 850 ): void { 851 //@ts-ignore 852 if (it.processName === 'render_service') { 853 //@ts-ignore 854 if (threadRow.name === `${it.processName} ${it.pid}`) { 855 this.renderRow = threadRow; 856 } 857 let flag = threads.length === index + 1 && !this.threadFuncMaxDepthMap.has(`${thread.upid}-${thread.tid}`); //@ts-ignore 858 processRow.sortRenderServiceData(threadRow, threadRow, threadRowArr, flag); 859 } else { 860 if (threadRow.rowId === threadRow.rowParentId) { 861 if (actualRow !== null) { 862 processRow.addChildTraceRowAfter(threadRow, actualRow); 863 } else if (expectedRow !== null) { 864 processRow.addChildTraceRowAfter(threadRow, expectedRow); 865 } else if (soRow) { 866 processRow.addChildTraceRowAfter(threadRow, soRow); 867 } else if (startupRow) { 868 processRow.addChildTraceRowAfter(threadRow, startupRow); 869 } else { 870 processRow.addChildTraceRowSpecifyLocation(threadRow, 0); 871 } 872 } else { 873 processRow.addChildTraceRow(threadRow); 874 } 875 } 876 } 877 878 addFuncStackRow( 879 process: unknown, 880 thread: unknown, 881 index: number, 882 threads: Array<unknown>, 883 threadRowArr: Array<unknown>, 884 threadRow: TraceRow<ThreadStruct>, 885 processRow: TraceRow<ProcessStruct> 886 ): void { 887 //@ts-ignore 888 if (this.threadFuncMaxDepthMap.get(`${thread.upid}-${thread.tid}`) !== undefined) { 889 //@ts-ignore 890 let max = this.threadFuncMaxDepthMap.get(`${thread.upid}-${thread.tid}`) || 1; 891 let maxHeight = max * 18 + 6; 892 let funcRow = TraceRow.skeleton<FuncStruct>(); //@ts-ignore 893 funcRow.rowId = `${thread.tid}`; 894 funcRow.rowType = TraceRow.ROW_TYPE_FUNC; 895 funcRow.enableCollapseChart(); //允许折叠泳道图 896 //@ts-ignore 897 funcRow.rowParentId = `${process.pid}`; 898 funcRow.rowHidden = !processRow.expansion; 899 funcRow.checkType = threadRow.checkType; 900 funcRow.style.width = '100%'; 901 funcRow.style.height = `${maxHeight}px`; //@ts-ignore 902 funcRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`; //@ts-ignore 903 funcRow.namePrefix = `${thread.threadName || 'Thread'}`; 904 funcRow.setAttribute('children', ''); 905 funcRow.supplierFrame = async (): Promise<Array<FuncStruct>> => { 906 //@ts-ignore 907 const rs = await funcDataSender(thread.tid || 0, thread.upid || 0, funcRow); //@ts-ignore 908 return this.funDataSenderCallback(rs, funcRow, thread); 909 }; 910 funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 911 funcRow.selectChangeHandler = this.trace.selectChangeHandler; 912 funcRow.findHoverStruct = (): void => { 913 FuncStruct.hoverFuncStruct = funcRow.getHoverStruct(); 914 }; 915 funcRow.onThreadHandler = rowThreadHandler<FuncRender>( 916 'func', 917 'context', 918 { 919 //@ts-ignore 920 type: `func${thread.tid}${thread.threadName}`, 921 }, 922 funcRow, 923 this.trace 924 ); //@ts-ignore 925 if (process.processName === 'render_service') { 926 let flag = threads.length === index + 1; //@ts-ignore 927 processRow.sortRenderServiceData(funcRow, threadRow, threadRowArr, flag); 928 } else { 929 processRow.addChildTraceRowAfter(funcRow, threadRow); 930 } 931 } 932 } 933 934 funDataSenderCallback( 935 rs: Array<unknown> | boolean, 936 funcRow: TraceRow<FuncStruct>, 937 thread: ThreadStruct 938 ): FuncStruct[] { 939 if (rs === true) { 940 funcRow.rowDiscard = true; 941 return []; 942 } else { 943 let funs = rs as FuncStruct[]; 944 if (funs.length > 0) { 945 funs.forEach((fun, index) => { 946 funs[index].itid = thread.utid; 947 funs[index].ipid = thread.upid; 948 funs[index].funName = this.funcNameMap.get(funs[index].id!); 949 if (Utils.isBinder(fun)) { 950 } else { 951 if (fun.nofinish) { 952 fun.flag = 'Did not end'; 953 } 954 } 955 }); 956 } else { 957 this.trace.refreshCanvas(true); 958 } 959 return funs; 960 } 961 } 962 963 //进程内存信息 964 addProcessMemInfo(it: { pid: number | null; processName: string | null }, processRow: TraceRow<ProcessStruct>): void { 965 //@ts-ignore 966 let processMem = this.processMem.filter((mem) => mem.pid === it.pid); 967 processMem.forEach((mem) => { 968 let row = TraceRow.skeleton<ProcessMemStruct>(); //@ts-ignore 969 row.rowId = `${mem.trackId}`; 970 row.rowType = TraceRow.ROW_TYPE_MEM; 971 row.rowParentId = `${it.pid}`; 972 row.rowHidden = !processRow.expansion; 973 row.style.height = '40px'; 974 row.style.width = '100%'; //@ts-ignore 975 row.name = `${mem.trackName}`; 976 row.setAttribute('children', ''); 977 row.favoriteChangeHandler = this.trace.favoriteChangeHandler; 978 row.selectChangeHandler = this.trace.selectChangeHandler; 979 row.focusHandler = (): void => { 980 this.trace.displayTip( 981 row, 982 ProcessMemStruct.hoverProcessMemStruct, 983 `<span>${ProcessMemStruct.hoverProcessMemStruct?.value || '0'}</span>` 984 ); 985 }; 986 row.findHoverStruct = (): void => { 987 ProcessMemStruct.hoverProcessMemStruct = row.getHoverStruct(false); 988 }; 989 row.supplierFrame = (): Promise<Array<ProcessMemStruct>> => //@ts-ignore 990 processMemDataSender(mem.trackId, row).then((resultProcess) => { 991 //@ts-ignore 992 let maxValue = this.filterIdMaxValue.get(mem.trackId) || 0; 993 for (let j = 0; j < resultProcess.length; j++) { 994 resultProcess[j].maxValue = maxValue; 995 if (j === resultProcess.length - 1) { 996 resultProcess[j].duration = (TraceRow.range?.totalNS || 0) - (resultProcess[j].startTime || 0); 997 } else { 998 resultProcess[j].duration = (resultProcess[j + 1].startTime || 0) - (resultProcess[j].startTime || 0); 999 } 1000 if (j > 0) { 1001 resultProcess[j].delta = (resultProcess[j].value || 0) - (resultProcess[j - 1].value || 0); 1002 } else { 1003 resultProcess[j].delta = 0; 1004 } 1005 } 1006 return resultProcess; 1007 }); 1008 row.onThreadHandler = rowThreadHandler<MemRender>( 1009 'mem', 1010 'context', 1011 { 1012 //@ts-ignore 1013 type: `mem ${mem.trackId} ${mem.trackName}`, 1014 }, 1015 row, 1016 this.trace 1017 ); 1018 if (this.renderRow && row.name === 'H:PreferredFrameRate') { 1019 processRow.addChildTraceRowBefore(row, this.renderRow); 1020 } else { 1021 processRow.addChildTraceRow(row); 1022 } 1023 }); 1024 } 1025 private calMaxHeight(asyncFunctions: unknown[]): number { 1026 let max = 0; 1027 asyncFunctions.forEach((it) => { 1028 //@ts-ignore 1029 const depth = it.depth || 0; 1030 if (depth > max) { 1031 max = depth; 1032 } 1033 }); 1034 max += 1; 1035 return max * 18 + 6; 1036 } 1037 1038 //Async Function 1039 addAsyncFunction(it: { pid: number; processName: string | null }, processRow: TraceRow<ProcessStruct>): void { 1040 //@ts-ignore 1041 let asyncFuncList = this.processAsyncFuncMap[it.pid] || []; 1042 let asyncFuncGroup = Utils.groupBy(asyncFuncList, 'funName'); // @ts-ignore 1043 Reflect.ownKeys(asyncFuncGroup).map((key: unknown) => { 1044 // @ts-ignore 1045 let asyncFunctions: Array<unknown> = asyncFuncGroup[key]; 1046 if (asyncFunctions.length > 0) { 1047 let isIntersect = (a: unknown, b: unknown): boolean => 1048 //@ts-ignore 1049 Math.max(a.startTs + a.dur, b.startTs + b.dur) - Math.min(a.startTs, b.startTs) < a.dur + b.dur; 1050 let depthArray: unknown = []; 1051 asyncFunctions.forEach((it, i) => { 1052 //@ts-ignore 1053 if (it.dur === -1 || it.dur === null || it.dur === undefined) { 1054 //@ts-ignore 1055 it.dur = (TraceRow.range?.endNS || 0) - it.startTs; //@ts-ignore 1056 it.flag = 'Did not end'; 1057 } 1058 let currentDepth = 0; 1059 let index = i; 1060 while ( 1061 //@ts-ignore 1062 depthArray[currentDepth] !== undefined && //@ts-ignore 1063 isIntersect(depthArray[currentDepth], asyncFunctions[index]) 1064 ) { 1065 currentDepth++; 1066 } //@ts-ignore 1067 asyncFunctions[index].depth = currentDepth; //@ts-ignore 1068 depthArray[currentDepth] = asyncFunctions[index]; 1069 }); 1070 const maxHeight = this.calMaxHeight(asyncFunctions); 1071 let funcRow = TraceRow.skeleton<FuncStruct>(); //@ts-ignore 1072 funcRow.rowId = `${asyncFunctions[0].funName}-${it.pid}`; //@ts-ignore 1073 funcRow.asyncFuncName = asyncFunctions[0].funName; 1074 funcRow.asyncFuncNamePID = it.pid; 1075 funcRow.rowType = TraceRow.ROW_TYPE_FUNC; 1076 funcRow.enableCollapseChart(); //允许折叠泳道图 1077 funcRow.rowParentId = `${it.pid}`; 1078 funcRow.rowHidden = !processRow.expansion; 1079 funcRow.style.width = '100%'; 1080 funcRow.style.height = `${maxHeight}px`; 1081 funcRow.setAttribute('height', `${maxHeight}`); //@ts-ignore 1082 funcRow.name = `${asyncFunctions[0].funName}`; 1083 funcRow.setAttribute('children', ''); 1084 funcRow.findHoverStruct = (): void => { 1085 FuncStruct.hoverFuncStruct = funcRow.getHoverStruct(); 1086 }; //@ts-ignore 1087 funcRow.supplier = (): Promise<unknown> => new Promise((resolve) => resolve(asyncFunctions)); 1088 funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 1089 funcRow.selectChangeHandler = this.trace.selectChangeHandler; 1090 funcRow.onThreadHandler = rowThreadHandler<FuncRender>( 1091 'func', 1092 'context', 1093 { 1094 //@ts-ignore 1095 type: `func-${asyncFunctions[0].funName}-${it.pid}`, 1096 }, 1097 funcRow, 1098 this.trace 1099 ); 1100 processRow.addChildTraceRow(funcRow); 1101 } 1102 }); 1103 } 1104} 1105