1/* 2 * Copyright (C) 2024 Shenzhen Kaihong Digital Industry Development 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 { TraceRow } from '../trace/base/TraceRow'; 18import { renders } from '../../database/ui-worker/ProcedureWorker'; 19import { info } from '../../../log/Log'; 20import { HangStruct } from '../../database/ui-worker/ProcedureWorkerHang'; 21import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 22import { queryHangData } from '../../database/sql/Hang.sql'; 23import { hangDataSender } from '../../database/data-trafic/HangDataSender'; 24import { BaseStruct } from '../../bean/BaseStruct'; 25import { Utils } from '../trace/base/Utils'; 26 27export type HangType = 'Instant' | 'Circumstantial' | 'Micro' | 'Severe' | ''; 28const TIME_MS = 1000000; 29/// Hangs聚合泳道 30export class SpHangChart { 31 private trace: SpSystemTrace; 32 static funcNameMap: Map<number | string, string> = new Map(); 33 34 constructor(trace: SpSystemTrace) { 35 this.trace = trace; 36 } 37 38 static calculateHangType(dur: number): HangType { 39 const durMS = dur / TIME_MS; 40 if (durMS < 33) { 41 return ''; 42 } 43 else if (durMS < 100) { 44 return 'Instant'; 45 } 46 else if (durMS < 250) { 47 return 'Circumstantial'; 48 } 49 else if (durMS < 500) { 50 return 'Micro'; 51 } 52 else { 53 return 'Severe'; 54 } 55 } 56 57 async init(): Promise<void> { 58 SpHangChart.funcNameMap = Utils.getInstance().getCallStatckMap(); 59 let folder = await this.initFolder(); 60 await this.initData(folder); 61 } 62 63 private hangSupplierFrame( 64 traceRow: TraceRow<HangStruct>, 65 it: { 66 id: number; 67 name: string; 68 num: number; 69 } 70 ): void { 71 traceRow.supplierFrame = (): Promise<HangStruct[]> => { 72 let promiseData = hangDataSender(it.id, traceRow); 73 if (promiseData === null) { 74 return new Promise<Array<HangStruct>>((resolve) => resolve([])); 75 } else { 76 return promiseData.then((resultHang: Array<HangStruct>) => 77 resultHang.map(hangItem => ({ 78 ...hangItem, 79 pname: it.name, 80 type: SpHangChart.calculateHangType(hangItem.dur!), 81 content: SpHangChart.funcNameMap.get(hangItem.id!) 82 })) 83 ); 84 } 85 }; 86 } 87 88 private hangThreadHandler( 89 traceRow: TraceRow<HangStruct>, 90 it: { 91 id: number; 92 name: string; 93 num: number; 94 }, 95 hangId: number 96 ): void { 97 traceRow.onThreadHandler = (useCache): void => { 98 let context: CanvasRenderingContext2D; 99 if (traceRow.currentContext) { 100 context = traceRow.currentContext; 101 } else { 102 context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 103 } 104 traceRow.canvasSave(context); 105 renders.hang.renderMainThread( 106 { 107 context: context, 108 useCache: useCache, 109 type: it.name, 110 index: hangId, 111 }, 112 traceRow 113 ); 114 traceRow.canvasRestore(context, this.trace); 115 }; 116 } 117 118 /// 初始化聚合泳道信息 119 async initData(folder: TraceRow<BaseStruct>): Promise<void> { 120 let hangStartTime = new Date().getTime(); 121 let hangList = await queryHangData(); 122 if (hangList.length === 0) { 123 return; 124 } 125 this.trace.rowsEL?.appendChild(folder); 126 for (let i = 0; i < hangList.length; i++) { 127 const it: { 128 id: number, 129 name: string, 130 num: number, 131 } = hangList[i]; 132 let traceRow = TraceRow.skeleton<HangStruct>(); 133 traceRow.rowId = `${it.name ?? 'Process'} ${it.id}`; 134 traceRow.rowType = TraceRow.ROW_TYPE_HANG; 135 traceRow.rowParentId = folder.rowId; 136 traceRow.style.height = '40px'; 137 traceRow.name = `${it.name ?? 'Process'} ${it.id}`; 138 traceRow.rowHidden = !folder.expansion; 139 traceRow.setAttribute('children', ''); 140 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 141 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 142 this.hangSupplierFrame(traceRow, it); 143 traceRow.getCacheData = (args: unknown): Promise<Array<unknown>> => hangDataSender(it.id, traceRow, args); 144 traceRow.focusHandler = (ev): void => { 145 let hangStruct = HangStruct.hoverHangStruct; 146 this.trace?.displayTip( 147 traceRow, hangStruct, 148 `<span>${hangStruct?.type} ${hangStruct?.dur! / TIME_MS}ms</span>` 149 ); 150 }; 151 traceRow.findHoverStruct = (): void => { 152 HangStruct.hoverHangStruct = traceRow.getHoverStruct(); 153 }; 154 this.hangThreadHandler(traceRow, it, i); 155 folder.addChildTraceRow(traceRow); 156 } 157 let durTime = new Date().getTime() - hangStartTime; 158 info('The time to load the HangData is: ', durTime); 159 } 160 161 async initFolder(): Promise<TraceRow<BaseStruct>> { 162 let hangFolder = TraceRow.skeleton(); 163 hangFolder.rowId = 'Hangs'; 164 hangFolder.index = 0; 165 hangFolder.rowType = TraceRow.ROW_TYPE_HANG_GROUP; 166 hangFolder.rowParentId = ''; 167 hangFolder.style.height = '40px'; 168 hangFolder.folder = true; 169 hangFolder.name = 'Hangs'; 170 hangFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 171 hangFolder.selectChangeHandler = this.trace.selectChangeHandler; // @ts-ignore 172 hangFolder.supplier = (): Promise<unknown[]> => new Promise<Array<unknown>>((resolve) => resolve([])); 173 hangFolder.onThreadHandler = (useCache): void => { 174 hangFolder.canvasSave(this.trace.canvasPanelCtx!); 175 if (hangFolder.expansion) { 176 // @ts-ignore 177 this.trace.canvasPanelCtx?.clearRect(0, 0, hangFolder.frame.width, hangFolder.frame.height); 178 } else { 179 (renders.empty as EmptyRender).renderMainThread( 180 { 181 context: this.trace.canvasPanelCtx, 182 useCache: useCache, 183 type: '', 184 }, 185 hangFolder 186 ); 187 } 188 hangFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace); 189 }; 190 return hangFolder; 191 } 192} 193