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 { info } from '../../../log/Log'; 18import { TraceRow } from '../trace/base/TraceRow'; 19import { procedurePool } from '../../database/Procedure'; 20import { CpuRender, CpuStruct } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 21import { renders } from '../../database/ui-worker/ProcedureWorker'; 22import { Utils } from '../trace/base/Utils'; 23import { cpuDataSender } from '../../database/data-trafic/CpuDataSender'; 24import { queryCpuCount, queryCpuMax, queryCpuSchedSlice } from '../../database/sql/Cpu.sql'; 25import { rowThreadHandler } from './SpChartManager'; 26 27export class SpCpuChart { 28 private trace: SpSystemTrace; 29 30 constructor(trace: SpSystemTrace) { 31 this.trace = trace; 32 } 33 34 private cpuSupplierFrame(traceRow: TraceRow<CpuStruct>, cpuId: number): void { 35 traceRow.supplierFrame = async (): Promise<CpuStruct[]> => { 36 const res = await cpuDataSender(cpuId, traceRow); 37 const filterList = SpSystemTrace.keyPathList.filter((item) => { 38 return item.cpu === cpuId; 39 }); 40 res.push(...filterList); 41 res.forEach((it, i, arr) => { 42 let p = Utils.getInstance().getProcessMap().get(it.processId!); 43 let t = Utils.getInstance().getThreadMap().get(it.tid!); 44 let slice = Utils.getInstance().getSchedSliceMap().get(`${it.id}-${it.startTime}`); 45 if (slice) { 46 it.end_state = slice.endState; 47 it.priority = slice.priority; 48 } 49 it.processName = p; 50 it.processCmdLine = p; 51 it.name = t; 52 it.type = 'thread'; 53 }); 54 return res; 55 }; 56 } 57 58 private cpuThreadHandler(traceRow: TraceRow<CpuStruct>, i1: number): void { 59 traceRow.onThreadHandler = (useCache: boolean, buf: ArrayBuffer | undefined | null): void => { 60 let context: CanvasRenderingContext2D; 61 if (traceRow.currentContext) { 62 context = traceRow.currentContext; 63 } else { 64 context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 65 } 66 traceRow.canvasSave(context); 67 (renders['cpu-data'] as CpuRender).renderMainThread( 68 { 69 ctx: context, 70 useCache: useCache, 71 type: `cpu-data-${i1}`, 72 translateY: traceRow.translateY, 73 }, 74 traceRow 75 ); 76 traceRow.canvasRestore(context, this.trace); 77 }; 78 } 79 80 // @ts-ignore 81 async init(cpuDataCount?: Map<number, number>, parentRow?: TraceRow<unknown>, traceId?: string): Promise<void> { 82 let CpuStartTime = new Date().getTime(); 83 let array = await queryCpuMax(traceId); 84 let cpuCountResult = await queryCpuCount(traceId); 85 if (cpuCountResult && cpuCountResult.length > 0 && cpuCountResult[0]) { 86 // @ts-ignore 87 Utils.getInstance().setWinCpuCount(cpuCountResult[0].cpuCount, traceId); 88 } else { 89 Utils.getInstance().setWinCpuCount(0, traceId); 90 } 91 let cpuSchedSlice = await queryCpuSchedSlice(traceId); 92 this.initSchedSliceData(cpuSchedSlice, traceId); 93 info('Cpu trace row data size is: ', array.length); 94 if (array && array.length > 0 && array[0]) { 95 //@ts-ignore 96 let cpuMax = array[0].cpu + 1; 97 Utils.getInstance().setCpuCount(cpuMax, traceId); 98 for (let i1 = 0; i1 < cpuMax; i1++) { 99 if (cpuDataCount && (cpuDataCount.get(i1) || 0) > 0) { 100 let traceRow = this.createCpuRow(i1, traceId); 101 if (parentRow) { 102 parentRow.addChildTraceRow(traceRow); 103 } else { 104 this.trace.rowsEL?.appendChild(traceRow); 105 } 106 } 107 } 108 } 109 let CpuDurTime = new Date().getTime() - CpuStartTime; 110 info('The time to load the Cpu data is: ', CpuDurTime); 111 } 112 113 createCpuRow(cpuId: number, traceId?: string): TraceRow<CpuStruct> { 114 let traceRow = TraceRow.skeleton<CpuStruct>(traceId); 115 traceRow.rowId = `${cpuId}`; 116 traceRow.rowType = TraceRow.ROW_TYPE_CPU; 117 traceRow.rowParentId = ''; 118 traceRow.style.height = '30px'; 119 traceRow.name = `Cpu ${cpuId}`; 120 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 121 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 122 traceRow.supplierFrame = async (): Promise<CpuStruct[]> => { 123 let res = await cpuDataSender(cpuId, traceRow, traceId); 124 const filterList = SpSystemTrace.keyPathList.filter((item): boolean => { 125 return item.cpu === cpuId; 126 }); 127 res.push(...filterList); 128 res.forEach((it, i, arr): void => { 129 let p = Utils.getInstance().getProcessMap(traceId).get(it.processId!); 130 let t = Utils.getInstance().getThreadMap(traceId).get(it.tid!); 131 let slice = Utils.getInstance().getSchedSliceMap(traceId).get(`${it.id}-${it.startTime}`); 132 if (slice) { 133 it.end_state = slice.endState; 134 it.priority = slice.priority; 135 } 136 it.processName = p; 137 it.processCmdLine = p; 138 it.name = t; 139 it.type = 'thread'; 140 }); 141 return res; 142 }; 143 traceRow.focusHandler = (): void => { 144 this.trace?.displayTip( 145 traceRow, 146 CpuStruct.hoverCpuStruct, 147 `<span>P:${CpuStruct.hoverCpuStruct?.processName || 'Process'} [${CpuStruct.hoverCpuStruct?.processId 148 }]</span><span>T:${CpuStruct.hoverCpuStruct?.name} [${CpuStruct.hoverCpuStruct?.tid}] [Prio:${CpuStruct.hoverCpuStruct?.priority || 0 149 }]</span>` 150 ); 151 }; 152 traceRow.findHoverStruct = (): void => { 153 CpuStruct.hoverCpuStruct = traceRow.getHoverStruct(); 154 }; 155 traceRow.onThreadHandler = rowThreadHandler<CpuRender>('cpu-data', 'ctx', { 156 type: `cpu-data-${cpuId}`, 157 translateY: traceRow.translateY, 158 }, traceRow, this.trace); 159 return traceRow; 160 } 161 162 initProcessThreadStateData = async (progress: Function): Promise<void> => { 163 let time = new Date().getTime(); 164 progress('StateProcessThread', 93); 165 procedurePool.submitWithName('logic0', 'spt-init', {}, undefined, (res: unknown) => { }); 166 let durTime = new Date().getTime() - time; 167 info('The time to load the first ProcessThreadState data is: ', durTime); 168 }; 169 170 initCpuIdle0Data = async (progress: Function): Promise<void> => { 171 let time = new Date().getTime(); 172 progress('CPU Idle', 94); 173 procedurePool.submitWithName( 174 'logic0', 175 'scheduling-getCpuIdle0', 176 { 177 // @ts-ignore 178 endTs: (window as unknown).recordEndNS, // @ts-ignore 179 total: (window as unknown).totalNS, 180 }, 181 undefined, 182 (res: unknown) => { } 183 ); 184 let durTime = new Date().getTime() - time; 185 info('The time to load the first CPU Idle0 data is: ', durTime); 186 }; 187 188 initSchedSliceData(arr: unknown[], traceId?: string): void { 189 Utils.getInstance().getSchedSliceMap(traceId).clear(); 190 arr.forEach((value) => { 191 Utils.getInstance().getSchedSliceMap(traceId). // @ts-ignore 192 set(`${value.itid}-${value.ts}`, { endState: value.endState, priority: value.priority }); 193 }); 194 } 195 196 initSchedulingPTData = async (progress: Function): Promise<void> => { 197 let time = new Date().getTime(); 198 progress('CPU Idle', 94); 199 procedurePool.submitWithName('logic0', 'scheduling-getProcessAndThread', {}, undefined, (res: unknown) => { }); 200 let durTime = new Date().getTime() - time; 201 info('The time to load the first CPU Idle0 data is: ', durTime); 202 }; 203 204 initSchedulingFreqData = async (progress: Function): Promise<void> => { 205 let time = new Date().getTime(); 206 progress('CPU Scheduling Freq', 94); 207 procedurePool.submitWithName('logic0', 'scheduling-initFreqData', {}, undefined, (res: unknown) => { }); 208 let durTime = new Date().getTime() - time; 209 info('The time to load the first CPU Idle0 data is: ', durTime); 210 }; 211} 212