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.js'; 17import { queryClockData, queryClockFrequency, queryClockState, queryScreenState } from '../../database/SqlLite.js'; 18import { TraceRow } from '../trace/base/TraceRow.js'; 19import { renders } from '../../database/ui-worker/ProcedureWorker.js'; 20import { info } from '../../../log/Log.js'; 21import { ClockRender, ClockStruct } from '../../database/ui-worker/ProcedureWorkerClock.js'; 22import { ColorUtils } from '../trace/base/ColorUtils.js'; 23import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; 24import { Utils } from '../trace/base/Utils.js'; 25 26export class SpClockChart { 27 private trace: SpSystemTrace; 28 29 constructor(trace: SpSystemTrace) { 30 this.trace = trace; 31 } 32 33 async init() { 34 let folder = await this.initFolder(); 35 await this.initData(folder); 36 } 37 38 async initData(folder: TraceRow<any>) { 39 let clockStartTime = new Date().getTime(); 40 let clockList = await queryClockData(); 41 if (clockList.length == 0) { 42 return; 43 } 44 info('clockList data size is: ', clockList!.length); 45 this.trace.rowsEL?.appendChild(folder); 46 ClockStruct.maxValue = clockList.map((item) => item.num).reduce((a, b) => Math.max(a, b)); 47 for (let i = 0; i < clockList.length; i++) { 48 const it = clockList[i]; 49 let maxValue = 0; 50 let traceRow = TraceRow.skeleton<ClockStruct>(); 51 let isState = it.name.endsWith(' State'); 52 let isScreenState = it.name.endsWith('ScreenState'); 53 traceRow.rowId = it.name; 54 traceRow.rowType = TraceRow.ROW_TYPE_CLOCK; 55 traceRow.rowParentId = folder.rowId; 56 traceRow.style.height = '40px'; 57 traceRow.name = it.name; 58 traceRow.rowHidden = !folder.expansion; 59 traceRow.setAttribute('children', ''); 60 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 61 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 62 traceRow.supplier = () => { 63 let promiseData = null; 64 if (it.name.endsWith(' Frequency')) { 65 promiseData = queryClockFrequency(it.srcname); 66 } else if (isState) { 67 promiseData = queryClockState(it.srcname); 68 } else if (isScreenState) { 69 promiseData = queryScreenState(); 70 } 71 if (promiseData == null) { 72 return new Promise<Array<any>>((resolve) => resolve([])); 73 } else { 74 return promiseData.then((resultClock) => { 75 for (let j = 0; j < resultClock.length; j++) { 76 if (!isState) { 77 if (j == resultClock.length - 1) { 78 resultClock[j].dur = (TraceRow.range?.totalNS || 0) - (resultClock[j].startNS || 0); 79 } else { 80 resultClock[j].dur = (resultClock[j + 1].startNS || 0) - (resultClock[j].startNS || 0); 81 } 82 } 83 if ((resultClock[j].value || 0) > maxValue) { 84 maxValue = resultClock[j].value || 0; 85 } 86 if (j > 0) { 87 resultClock[j].delta = (resultClock[j].value || 0) - (resultClock[j - 1].value || 0); 88 } else { 89 resultClock[j].delta = 0; 90 } 91 } 92 return resultClock; 93 }); 94 } 95 }; 96 traceRow.focusHandler = (ev) => { 97 this.trace?.displayTip( 98 traceRow, 99 ClockStruct.hoverClockStruct, 100 `<span>${ColorUtils.formatNumberComma(ClockStruct.hoverClockStruct?.value!)}</span>` 101 ); 102 }; 103 traceRow.onThreadHandler = (useCache) => { 104 let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 105 traceRow.canvasSave(context); 106 (renders['clock'] as ClockRender).renderMainThread( 107 { 108 context: context, 109 useCache: useCache, 110 type: it.name, 111 maxValue: maxValue === 0 ? 1 : maxValue, 112 index: i, 113 maxName: 114 isState || isScreenState ? maxValue.toString() : Utils.getFrequencyWithUnit(maxValue / 1000).maxFreqName, 115 }, 116 traceRow 117 ); 118 traceRow.canvasRestore(context); 119 }; 120 folder.addChildTraceRow(traceRow); 121 } 122 let durTime = new Date().getTime() - clockStartTime; 123 info('The time to load the ClockData is: ', durTime); 124 } 125 126 async initFolder(): Promise<TraceRow<any>> { 127 let clockFolder = TraceRow.skeleton(); 128 clockFolder.rowId = `Clocks`; 129 clockFolder.index = 0; 130 clockFolder.rowType = TraceRow.ROW_TYPE_CLOCK_GROUP; 131 clockFolder.rowParentId = ''; 132 clockFolder.style.height = '40px'; 133 clockFolder.folder = true; 134 clockFolder.name = `Clocks`; /* & I/O Latency */ 135 clockFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 136 clockFolder.selectChangeHandler = this.trace.selectChangeHandler; 137 clockFolder.supplier = () => new Promise<Array<any>>((resolve) => resolve([])); 138 clockFolder.onThreadHandler = (useCache) => { 139 clockFolder.canvasSave(this.trace.canvasPanelCtx!); 140 if (clockFolder.expansion) { 141 this.trace.canvasPanelCtx?.clearRect(0, 0, clockFolder.frame.width, clockFolder.frame.height); 142 } else { 143 (renders['empty'] as EmptyRender).renderMainThread( 144 { 145 context: this.trace.canvasPanelCtx, 146 useCache: useCache, 147 type: ``, 148 }, 149 clockFolder 150 ); 151 } 152 clockFolder.canvasRestore(this.trace.canvasPanelCtx!); 153 }; 154 return clockFolder; 155 } 156} 157