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 { TraceRow } from '../trace/base/TraceRow'; 18import { renders } from '../../database/ui-worker/ProcedureWorker'; 19import { info } from '../../../log/Log'; 20import { ClockRender, ClockStruct } from '../../database/ui-worker/ProcedureWorkerClock'; 21import { ColorUtils } from '../trace/base/ColorUtils'; 22import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 23import { Utils } from '../trace/base/Utils'; 24import { clockDataSender } from '../../database/data-trafic/ClockDataSender'; 25import { queryClockData } from '../../database/sql/Clock.sql'; 26import { DmaFenceRender, DmaFenceStruct } from '../../database/ui-worker/ProcedureWorkerDmaFence'; 27import { dmaFenceSender } from '../../database/data-trafic/dmaFenceSender'; 28import { queryDmaFenceName } from '../../database/sql/dmaFence.sql'; 29import { BaseStruct } from '../../bean/BaseStruct'; 30import { promises } from 'dns'; 31 32export class SpClockChart { 33 private readonly trace: SpSystemTrace; 34 35 constructor(trace: SpSystemTrace) { 36 this.trace = trace; 37 } 38 39 async init(parentRow?: TraceRow<BaseStruct>, traceId?: string): Promise<void> { 40 let clockList = await queryClockData(traceId); 41 if (clockList.length === 0) { 42 return; 43 } 44 let folder = await this.initFolder(traceId); 45 if (parentRow) { 46 parentRow.addChildTraceRow(folder); 47 } else { 48 this.trace.rowsEL?.appendChild(folder); 49 } 50 await this.initData(folder, clockList, traceId); 51 await this.initDmaFence(folder); 52 } 53 54 private clockSupplierFrame( 55 traceRow: TraceRow<ClockStruct>, 56 it: { 57 name: string; 58 num: number; 59 srcname: string; 60 maxValue?: number; 61 }, 62 isState: boolean, 63 isScreenState: boolean, 64 ): void { 65 traceRow.supplierFrame = (): Promise<ClockStruct[]> => { 66 let promiseData = null; 67 if (it.name.endsWith(' Frequency')) { 68 promiseData = clockDataSender(it.srcname, 'clockFrequency', traceRow); 69 } else if (isState) { 70 promiseData = clockDataSender(it.srcname, 'clockState', traceRow); 71 } else if (isScreenState) { 72 promiseData = clockDataSender('', 'screenState', traceRow); 73 } 74 if (promiseData === null) { 75 // @ts-ignore 76 return new Promise<Array<unknown>>((resolve) => resolve([])); 77 } else { 78 // @ts-ignore 79 return promiseData.then((resultClock: Array<unknown>) => { 80 for (let j = 0; j < resultClock.length; j++) { 81 // @ts-ignore 82 resultClock[j].type = 'measure'; // @ts-ignore 83 if ((resultClock[j].value || 0) > it.maxValue!) { 84 // @ts-ignore 85 it.maxValue = resultClock[j].value || 0; 86 } 87 if (j > 0) { 88 // @ts-ignore 89 resultClock[j].delta = (resultClock[j].value || 0) - (resultClock[j - 1].value || 0); 90 } else { 91 // @ts-ignore 92 resultClock[j].delta = 0; 93 } 94 } 95 return resultClock; 96 }); 97 } 98 }; 99 } 100 101 private clockThreadHandler( 102 traceRow: TraceRow<ClockStruct>, 103 it: { 104 name: string; 105 num: number; 106 srcname: string; 107 maxValue?: number; 108 }, 109 isState: boolean, 110 isScreenState: boolean, 111 clockId: number 112 ): void { 113 traceRow.onThreadHandler = (useCache): void => { 114 let context: CanvasRenderingContext2D; 115 if (traceRow.currentContext) { 116 context = traceRow.currentContext; 117 } else { 118 context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 119 } 120 traceRow.canvasSave(context); 121 (renders.clock as ClockRender).renderMainThread( 122 { 123 context: context, 124 useCache: useCache, 125 type: it.name, 126 maxValue: it.maxValue === 0 ? 1 : it.maxValue!, 127 index: clockId, 128 maxName: 129 isState || isScreenState 130 ? it.maxValue!.toString() 131 : Utils.getFrequencyWithUnit(it.maxValue! / 1000).maxFreqName, 132 }, 133 traceRow 134 ); 135 traceRow.canvasRestore(context, this.trace); 136 }; 137 } 138 139 async initData(folder: TraceRow<BaseStruct>, clockList: Array<{ 140 name: string; 141 num: number; 142 srcname: string; 143 maxValue?: number; 144 }>, traceId?: string): Promise<void> { 145 let clockStartTime = new Date().getTime(); 146 info('clockList data size is: ', clockList!.length); 147 if (!traceId) { 148 this.trace.rowsEL?.appendChild(folder); 149 } 150 ClockStruct.maxValue = clockList.map((item) => item.num).reduce((a, b) => Math.max(a, b)); 151 for (let i = 0; i < clockList.length; i++) { 152 const it = clockList[i]; 153 it.maxValue = 0; 154 let traceRow = TraceRow.skeleton<ClockStruct>(traceId); 155 let isState = it.name.endsWith(' State'); 156 let isScreenState = it.name.endsWith('ScreenState'); 157 traceRow.rowId = it.name; 158 traceRow.rowType = TraceRow.ROW_TYPE_CLOCK; 159 traceRow.rowParentId = folder.rowId; 160 traceRow.style.height = '40px'; 161 traceRow.name = it.name; 162 traceRow.rowHidden = !folder.expansion; 163 traceRow.setAttribute('children', ''); 164 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 165 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 166 this.clockSupplierFrame(traceRow, it, isState, isScreenState); 167 traceRow.getCacheData = (args: unknown): Promise<ClockStruct[]> | undefined => { 168 let result: Promise<ClockStruct[]> | undefined; 169 if (it.name.endsWith(' Frequency')) { 170 result = clockDataSender(it.srcname, 'clockFrequency', traceRow, args); 171 } else if (isState) { 172 result = clockDataSender(it.srcname, 'clockState', traceRow, args); 173 } else if (isScreenState) { 174 result = clockDataSender('', 'screenState', traceRow, args); 175 } 176 return result; 177 }; 178 traceRow.focusHandler = (ev): void => { 179 this.trace?.displayTip( 180 traceRow, 181 ClockStruct.hoverClockStruct, 182 `<span>${ColorUtils.formatNumberComma(ClockStruct.hoverClockStruct?.value!)}</span>` 183 ); 184 }; 185 traceRow.findHoverStruct = (): void => { 186 ClockStruct.hoverClockStruct = traceRow.getHoverStruct(); 187 }; 188 this.clockThreadHandler(traceRow, it, isState, isScreenState, i); 189 folder.addChildTraceRow(traceRow); 190 } 191 let durTime = new Date().getTime() - clockStartTime; 192 info('The time to load the ClockData is: ', durTime); 193 } 194 195 // @ts-ignore 196 async initDmaFence(folder: TraceRow<unknown>): Promise<void> { 197 let dmaFenceNameList = await queryDmaFenceName(); 198 if (dmaFenceNameList.length) { 199 let dmaFenceList = []; 200 const timelineValues = dmaFenceNameList.map(obj => obj.timeline); 201 for (let i = 0; i < timelineValues.length; i++) { 202 let traceRow: TraceRow<DmaFenceStruct> = TraceRow.skeleton<DmaFenceStruct>(); 203 traceRow.rowId = timelineValues[i]; 204 traceRow.rowType = TraceRow.ROW_TYPE_DMA_FENCE; 205 traceRow.rowParentId = folder.rowId; 206 traceRow.style.height = 40 + 'px'; 207 traceRow.name = `${timelineValues[i]}`; 208 traceRow.folder = false; 209 traceRow.rowHidden = !folder.expansion; 210 traceRow.setAttribute('children', ''); 211 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 212 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 213 // @ts-ignore 214 traceRow.supplierFrame = (): Promise<DmaFenceStruct[]> => { 215 return dmaFenceSender('dma_fence_init', `${timelineValues[i]}`, traceRow).then((res) => { 216 res.forEach((item: unknown) => { 217 // @ts-ignore 218 let detail = Utils.DMAFENCECAT_MAP.get(item.id!); 219 if (detail) { 220 let catValue = (detail.cat.match(/^dma_(.*)$/))![1]; 221 // @ts-ignore 222 item.sliceName = catValue.endsWith('ed') ? `${catValue.slice(0, -2)}(${detail.seqno})` : `${catValue}(${detail.seqno})`; 223 // @ts-ignore 224 item.driver = detail.driver; 225 // @ts-ignore 226 item.context = detail.context; 227 // @ts-ignore 228 item.depth = 0; 229 } 230 231 }); 232 return dmaFenceList = res; 233 }); 234 235 }; 236 traceRow.onThreadHandler = (useCache): void => { 237 let context: CanvasRenderingContext2D; 238 if (traceRow.currentContext) { 239 context = traceRow.currentContext; 240 } else { 241 context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 242 } 243 traceRow.canvasSave(context); 244 (renders.dmaFence as DmaFenceRender).renderMainThread( 245 { 246 dmaFenceContext: context, 247 useCache: useCache, 248 type: 'dmaFence', 249 maxValue: 20, 250 index: 1, 251 maxName: '' 252 }, 253 traceRow 254 ); 255 traceRow.canvasRestore(context, this.trace); 256 }; 257 folder.addChildTraceRow(traceRow); 258 } 259 260 } 261 262 } 263 264 265 async initFolder(traceId?: string): Promise<TraceRow<BaseStruct>> { 266 let clockFolder = TraceRow.skeleton(traceId); 267 clockFolder.rowId = 'Clocks'; 268 clockFolder.index = 0; 269 clockFolder.rowType = TraceRow.ROW_TYPE_CLOCK_GROUP; 270 clockFolder.rowParentId = ''; 271 clockFolder.style.height = '40px'; 272 clockFolder.folder = true; 273 clockFolder.name = 'Clocks'; 274 clockFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 275 clockFolder.selectChangeHandler = this.trace.selectChangeHandler; 276 clockFolder.supplier = (): Promise<BaseStruct[]> => new Promise<Array<BaseStruct>>((resolve) => resolve([])); 277 clockFolder.onThreadHandler = (useCache): void => { 278 clockFolder.canvasSave(this.trace.canvasPanelCtx!); 279 if (clockFolder.expansion) { 280 this.trace.canvasPanelCtx?.clearRect(0, 0, clockFolder.frame.width, clockFolder.frame.height); 281 } else { 282 (renders.empty as EmptyRender).renderMainThread( 283 { 284 context: this.trace.canvasPanelCtx, 285 useCache: useCache, 286 type: '', 287 }, 288 clockFolder 289 ); 290 } 291 clockFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace); 292 }; 293 return clockFolder; 294 } 295} 296