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