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 { TraceRow } from '../trace/base/TraceRow.js'; 18 19import { BaseStruct } from '../../bean/BaseStruct.js'; 20import { 21 queryCounterMax, 22 querySdkCount, 23 querySdkCounterData, 24 querySdkSliceData, 25 queryStartTime, 26} from '../../database/SqlLite.js'; 27import { CounterStruct, SdkCounterRender } from '../../database/ui-worker/ProduceWorkerSdkCounter.js'; 28import { renders } from '../../database/ui-worker/ProcedureWorker.js'; 29import { SdkSliceRender, SdkSliceStruct } from '../../database/ui-worker/ProduceWorkerSdkSlice.js'; 30import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; 31import { TabUtil } from '../trace/sheet/sdk/TabUtil.js'; 32 33export class SpSdkChart { 34 private trace: SpSystemTrace; 35 private pluginName = 'dubai-plugin'; 36 37 constructor(trace: SpSystemTrace) { 38 this.trace = trace; 39 } 40 41 parseJson(startTime: number, map: Map<number, string>) { 42 let tablesMap = new Map(); 43 let keys = map.keys(); 44 for (let key of keys) { 45 let table = []; 46 let configObj: any = map.get(key); 47 if (configObj != undefined) { 48 let configStr = configObj.jsonConfig; 49 let json = JSON.parse(configStr); 50 let tableConfig = json.tableConfig; 51 if (tableConfig != null) { 52 let showTypes = tableConfig.showType; 53 for (let i = 0; i < showTypes.length; i++) { 54 let showType = showTypes[i]; 55 let type = TabUtil.getTableType(showType); 56 if (type == 'counter') { 57 let chartSql = this.createSql( 58 startTime, 59 showType.tableName, 60 showType.columns, 61 'where counter_id' + ' = $counter_id' 62 ); 63 let maxValue = this.createMaxValueSql(showType.tableName, 'where counter_id = $counter_id'); 64 let innerTable = showType.inner; 65 let countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns); 66 table.push({ 67 countSql: countSql, 68 chartSql: chartSql, 69 maxSql: maxValue, 70 type: 'counter', 71 name: configObj.disPlayName, 72 pluginName: configObj.pluginName, 73 }); 74 } else if (type == 'slice') { 75 let chartSql = this.createSliceSql( 76 startTime, 77 showType.tableName, 78 showType.columns, 79 'where' + ' slice_id = $column_id and (start_ts - ' + startTime + ') between $startNS and $endNS;' 80 ); 81 let innerTable = showType.inner; 82 let countSql; 83 let countOtherSql = ''; 84 if (configObj.pluginName == this.pluginName) { 85 countSql = this.createSql( 86 startTime, 87 innerTable.tableName, 88 innerTable.columns, 89 'where slice_name like $suffix' 90 ); 91 countOtherSql = this.createSql( 92 startTime, 93 innerTable.tableName, 94 innerTable.columns, 95 '' + 96 "where slice_name not like '%_cpu' and slice_name not like '%_display' and slice_name not like '%_gpu'" + 97 "and slice_name not like '%_System_idle' and slice_name not like '%_wifi_data' " + 98 "and slice_name not like '%_sensor' and slice_name not like '%_audio' " 99 ); 100 } else { 101 countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns); 102 } 103 table.push({ 104 countSql: countSql, 105 chartSql: chartSql, 106 type: 'slice', 107 name: configObj.disPlayName, 108 pluginName: configObj.pluginName, 109 countOtherSql: countOtherSql, 110 }); 111 } 112 } 113 tablesMap.set(key, table); 114 } 115 } 116 } 117 return tablesMap; 118 } 119 120 private createSliceSql(startTime: number, tableName: string, columns: Array<any>, where?: string): string { 121 let sliceSelectSql = 'select '; 122 for (let i = 0; i < columns.length; i++) { 123 let column = columns[i]; 124 if (column.column == 'start_ts') { 125 column.column = '(start_ts - ' + startTime + ') AS start_ts'; 126 } 127 if (column.column == 'end_ts') { 128 column.column = '(end_ts - ' + startTime + ') AS end_ts'; 129 } 130 if (i == columns.length - 1) { 131 sliceSelectSql = sliceSelectSql + column.column + ' '; 132 } else { 133 sliceSelectSql = sliceSelectSql + column.column + ', '; 134 } 135 } 136 sliceSelectSql = sliceSelectSql + 'from ' + tableName; 137 if (where != undefined) { 138 sliceSelectSql = sliceSelectSql + ' ' + where; 139 } 140 return sliceSelectSql; 141 } 142 143 private createMaxValueSql(tableName: string, where?: string): string { 144 let selectSql = 'select max(value) as max_value from ' + tableName; 145 if (where != undefined) { 146 selectSql = selectSql + ' ' + where; 147 } 148 return selectSql; 149 } 150 151 private createSql(startTime: number, tableName: string, columns: Array<any>, where?: string): string { 152 let selectSql = 'select '; 153 for (let i = 0; i < columns.length; i++) { 154 let column = columns[i]; 155 if (column.column == 'ts') { 156 column.column = 'ts - ' + startTime + ' AS ts'; 157 } 158 if (i == columns.length - 1) { 159 selectSql = selectSql + column.column + ' '; 160 } else { 161 selectSql = selectSql + column.column + ', '; 162 } 163 } 164 selectSql = selectSql + 'from ' + tableName; 165 if (where != undefined) { 166 selectSql = selectSql + ' ' + where; 167 } 168 return selectSql; 169 } 170 171 async init() { 172 let configMap = SpSystemTrace.SDK_CONFIG_MAP; 173 if (configMap == undefined) return; 174 let res = await queryStartTime(); 175 let startTime = res[0].start_ts; 176 let tablesMap = this.parseJson(startTime, configMap); 177 let tableKeys = tablesMap.keys(); 178 for (let componentId of tableKeys) { 179 let table = tablesMap.get(componentId); 180 if (table != null) { 181 let nodeRow = this.initNodeRow(componentId, table[0].name); 182 for (let index = 0; index < table.length; index++) { 183 let sqlMap = table[index]; 184 if (sqlMap.type == 'counter') { 185 let result = await querySdkCount(sqlMap.countSql, componentId); 186 for (let i = 0; i < result.length; i++) { 187 await this.initCounter(nodeRow, i, result[i], sqlMap, componentId); 188 } 189 } else if (sqlMap.type == 'slice' && sqlMap.pluginName == this.pluginName) { 190 let suffixList = ['cpu', 'display', 'gpu', 'System_idle', 'wifi_data', 'sensor', 'audio']; 191 for (let i = 0; i < suffixList.length; i++) { 192 let result = await querySdkCount(sqlMap.countSql, componentId, { $suffix: '%' + suffixList[i] }); 193 if (result.length > 0) { 194 let groupNodeRow = await this.initSecondaryRow(nodeRow, i, suffixList[i]); 195 for (let i = 0; i < result.length; i++) { 196 await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId); 197 } 198 } 199 } 200 let result = await querySdkCount(sqlMap.countOtherSql, componentId); 201 if (result.length > 0) { 202 let groupNodeRow = await this.initSecondaryRow(nodeRow, 7, 'other'); 203 for (let i = 0; i < result.length; i++) { 204 await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId); 205 } 206 } 207 } else if (sqlMap.type == 'slice') { 208 let result = await querySdkCount(sqlMap.countSql, componentId, {}); 209 for (let i = 0; i < result.length; i++) { 210 await this.initSlice(nodeRow, i, result[i], sqlMap, componentId); 211 } 212 } 213 } 214 } 215 } 216 } 217 218 private initCounter = async ( 219 nodeRow: TraceRow<BaseStruct>, 220 index: number, 221 result: any, 222 sqlMap: any, 223 componentId: number 224 ) => { 225 let traceRow = TraceRow.skeleton<CounterStruct>(); 226 traceRow.rowParentId = `Sdk-${componentId}`; 227 traceRow.rowHidden = !nodeRow.expansion; 228 traceRow.rowId = result.counter_id + '-' + componentId; 229 traceRow.rowType = TraceRow.ROW_TYPE_SDK_COUNTER; 230 traceRow.folderPaddingLeft = 30; 231 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 232 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 233 traceRow.style.height = '40px'; 234 traceRow.style.width = `100%`; 235 traceRow.setAttribute('children', ''); 236 traceRow.name = `${result.counter_name}`; 237 traceRow.supplier = () => querySdkCounterData(sqlMap.chartSql, result.counter_id, componentId); 238 traceRow.focusHandler = () => { 239 this.trace?.displayTip( 240 traceRow, 241 CounterStruct.hoverCounterStruct, 242 `<span>${CounterStruct.hoverCounterStruct?.value?.toFixed(2)}</span>` 243 ); 244 }; 245 let maxList = await queryCounterMax(sqlMap.maxSql, result.counter_id, componentId); 246 let maxCounter = maxList[0].max_value; 247 traceRow.onThreadHandler = (useCache) => { 248 let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 249 traceRow.canvasSave(context); 250 (renders[TraceRow.ROW_TYPE_SDK_COUNTER] as SdkCounterRender).renderMainThread( 251 { 252 context: context, 253 useCache: useCache, 254 type: `sdk-counter-${index}`, 255 maxName: `${maxCounter}`, 256 maxValue: maxCounter, 257 }, 258 traceRow 259 ); 260 traceRow.canvasRestore(context); 261 }; 262 nodeRow.addChildTraceRow(traceRow); 263 }; 264 265 private initNodeRow = (index: number, name: string) => { 266 let sdkFolder = TraceRow.skeleton(); 267 sdkFolder.rowId = `Sdk-${index}`; 268 sdkFolder.index = index; 269 sdkFolder.rowType = TraceRow.ROW_TYPE_SDK; 270 sdkFolder.rowParentId = ''; 271 sdkFolder.style.height = '40px'; 272 sdkFolder.folder = true; 273 sdkFolder.name = `${name}`; 274 sdkFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 275 sdkFolder.selectChangeHandler = this.trace.selectChangeHandler; 276 sdkFolder.supplier = () => new Promise<Array<any>>((resolve) => resolve([])); 277 sdkFolder.onThreadHandler = (useCache) => { 278 sdkFolder.canvasSave(this.trace.canvasPanelCtx!); 279 if (sdkFolder.expansion) { 280 this.trace.canvasPanelCtx?.clearRect(0, 0, sdkFolder.frame.width, sdkFolder.frame.height); 281 } else { 282 (renders['empty'] as EmptyRender).renderMainThread( 283 { 284 context: this.trace.canvasPanelCtx, 285 useCache: useCache, 286 type: ``, 287 }, 288 sdkFolder 289 ); 290 } 291 sdkFolder.canvasRestore(this.trace.canvasPanelCtx!); 292 }; 293 this.trace.rowsEL?.appendChild(sdkFolder); 294 return sdkFolder; 295 }; 296 297 private initSecondaryRow = async (nodeRow: TraceRow<BaseStruct>, index: number, name: string) => { 298 let sdkSecondFolder = TraceRow.skeleton(); 299 sdkSecondFolder.rowId = `Sdk-${name}-${index}`; 300 sdkSecondFolder.index = index; 301 sdkSecondFolder.rowType = TraceRow.ROW_TYPE_SDK; 302 sdkSecondFolder.rowParentId = nodeRow.rowId; 303 sdkSecondFolder.rowHidden = !nodeRow.expansion; 304 sdkSecondFolder.style.height = '40px'; 305 sdkSecondFolder.folder = true; 306 sdkSecondFolder.folderPaddingLeft = 30; 307 sdkSecondFolder.name = `${name}`; 308 sdkSecondFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler; 309 sdkSecondFolder.selectChangeHandler = this.trace.selectChangeHandler; 310 sdkSecondFolder.supplier = () => new Promise<Array<any>>((resolve) => resolve([])); 311 sdkSecondFolder.onThreadHandler = (useCache) => { 312 sdkSecondFolder.canvasSave(this.trace.canvasPanelCtx!); 313 if (sdkSecondFolder.expansion) { 314 this.trace.canvasPanelCtx?.clearRect(0, 0, sdkSecondFolder.frame.width, sdkSecondFolder.frame.height); 315 } else { 316 (renders['empty'] as EmptyRender).renderMainThread( 317 { 318 context: this.trace.canvasPanelCtx, 319 useCache: useCache, 320 type: ``, 321 }, 322 sdkSecondFolder 323 ); 324 } 325 sdkSecondFolder.canvasRestore(this.trace.canvasPanelCtx!); 326 }; 327 this.trace.rowsEL?.appendChild(sdkSecondFolder); 328 return sdkSecondFolder; 329 }; 330 331 private initSlice = async ( 332 nodeRow: TraceRow<BaseStruct>, 333 index: number, 334 result: any, 335 sqlMap: any, 336 componentId: number 337 ) => { 338 let traceRow = TraceRow.skeleton<SdkSliceStruct>(); 339 traceRow.rowType = TraceRow.ROW_TYPE_SDK_SLICE; 340 traceRow.rowHidden = !nodeRow.expansion; 341 traceRow.rowParentId = nodeRow.rowId; 342 traceRow.folderPaddingLeft = 30; 343 traceRow.style.height = '40px'; 344 traceRow.style.width = `100%`; 345 traceRow.name = `${result.slice_name}`; 346 traceRow.setAttribute('children', ''); 347 traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 348 traceRow.selectChangeHandler = this.trace.selectChangeHandler; 349 traceRow.rowId = result.slice_id + '-' + componentId; 350 traceRow.supplier = () => 351 querySdkSliceData( 352 sqlMap.chartSql, 353 result.slice_id, 354 TraceRow.range?.startNS || 0, 355 TraceRow.range?.endNS || 0, 356 componentId 357 ); 358 traceRow.focusHandler = () => { 359 this.trace?.displayTip( 360 traceRow, 361 SdkSliceStruct.hoverSdkSliceStruct, 362 `<span>${SdkSliceStruct.hoverSdkSliceStruct?.value}</span>` 363 ); 364 }; 365 traceRow.onThreadHandler = (useCache: boolean) => { 366 let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 367 traceRow.canvasSave(context); 368 (renders[TraceRow.ROW_TYPE_SDK_SLICE] as SdkSliceRender).renderMainThread( 369 { 370 context: context, 371 useCache: useCache, 372 type: `sdk-slice-${index}`, 373 maxName: '', 374 maxValue: 0, 375 }, 376 traceRow 377 ); 378 traceRow.canvasRestore(context); 379 }; 380 nodeRow.addChildTraceRow(traceRow); 381 }; 382} 383