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 */ 15import { query } from '../../database/SqlLite'; 16import { TraceRow } from '../trace/base/TraceRow'; 17import { FlagsConfig } from '../../component/SpFlags'; 18interface VSyncData { 19 startTime: number; 20 dur: number; 21 value?: number; 22} 23 24let vSyncDataList: VSyncData[] = []; 25let vSyncEnable = false; 26let isSingle = false; 27 28export function resetVSync(): void { 29 vSyncEnable = false; 30} 31 32export const querySfVSyncData = (): Promise<Array<VSyncData>> => 33 query( 34 'querySfVSyncData', 35 `SELECT value, c.ts - tb.start_ts startTime 36 FROM process_measure c, 37 trace_range tb 38 WHERE c.filter_id IN (SELECT process_measure_filter.id AS traceId 39 FROM process_measure_filter 40 JOIN process USING (ipid) 41 WHERE process.name = ${ 42 `'` + 43 String.fromCharCode(115, 117, 114, 102, 97, 99, 101, 102, 108, 105, 110, 103, 101, 114) + 44 `'` 45 } 46 AND process_measure_filter.name = ${ 47 `'` + String.fromCharCode(86, 83, 89, 78, 67, 45, 97, 112, 112) + `'` 48 })` 49 ); 50 51 export const querySingleVSyncData = (): Promise<Array<VSyncData>> => { 52 let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY); 53 let flagsItemJson = JSON.parse(flagsItem!); 54 let vsyncValue = flagsItemJson.vsyncValue; 55 let vsyncCondition = ''; 56 if (vsyncValue === 'H:VsyncGenerator' || vsyncValue === '') { 57 vsyncCondition = ` AND (callstack.name like 'H:GenerateVsyncCount%'))`; 58 } else { 59 vsyncCondition = ` AND callstack.name like '${vsyncValue}%' )`; 60 } 61 62 let sql = 63 `SELECT c.ts - tb.start_ts startTime 64 FROM callstack c, 65 trace_range tb 66 WHERE c.id IN (SELECT callstack.id AS trackId 67 FROM callstack 68 JOIN process 69 WHERE process.name = 'render_service'` 70 + vsyncCondition; 71 return query('querySingleVSyncData', sql); 72 } 73 74/** 75 * load single vsync data 76 */ 77export async function setVSyncData(): Promise<void> { 78 let sfvSyncData = await querySfVSyncData(); 79 if (sfvSyncData.length === 0) { 80 sfvSyncData = await querySingleVSyncData(); 81 isSingle = true; 82 } 83 sfvSyncData.forEach((it, index, array): void => { 84 if (index < array.length - 1) { 85 it.dur = array[index + 1].startTime - it.startTime; 86 } else { 87 it.dur = window.totalNS - it.startTime; 88 } 89 }); 90 vSyncDataList = sfvSyncData; 91} 92 93/** 94 * draw chart 95 */ 96export function drawVSync(ctx: CanvasRenderingContext2D, width: number, height: number): void { 97 if (!vSyncEnable) { 98 return; 99 } 100 function draw(it: VSyncData): void { 101 let x = ns2x(it.startTime, width); 102 let x2 = ns2x(it.startTime + it.dur, width); 103 ctx.fillRect(x, 0, x2 - x, height); 104 } 105 ctx.beginPath(); 106 ctx.fillStyle = '#555555'; 107 ctx.lineWidth = 1; 108 ctx.globalAlpha = 0.3; 109 if (isSingle) { 110 // 单框架灰白交替 111 for (let i = 0; i < vSyncDataList.length; i++) { 112 if (i % 2 === 1) { 113 continue; 114 } 115 draw(vSyncDataList[i]); 116 } 117 } else { 118 // 双框架绘制vSync 信号为1的数据为灰 119 vSyncDataList 120 ?.filter((it) => it.value === 1) 121 .forEach((it) => { 122 draw(it); 123 }); 124 } 125 ctx.stroke(); 126 ctx.globalAlpha = 1.0; 127 ctx.closePath(); 128} 129 130/** 131 * enable/disable SingleVSync 132 */ 133export function enableVSync(press: boolean, ev: KeyboardEvent, handler?: Function): void { 134 if (ev.key.toLocaleLowerCase() === 'v' && !ev.ctrlKey) { 135 window.publish(window.SmartEvent.UI.Loading, { loading: true, text: 'Query VSync' }); 136 setVSyncData(); 137 window.publish(window.SmartEvent.UI.Loading, { loading: false, text: 'Query VSync' }); 138 vSyncEnable = !vSyncEnable; 139 handler?.(); 140 } 141} 142 143/** 144 * ns to px 145 */ 146function ns2x(ns: number, width: number): number { 147 let startNS = TraceRow.range?.startNS || 0; 148 let endNS = TraceRow.range?.endNS || 0; 149 if (endNS === 0) { 150 //@ts-ignore 151 endNS = (window as unknown).totalNS; 152 } 153 let xWidth: number = ((ns - startNS) * width) / (endNS - startNS); 154 if (xWidth < 0) { 155 xWidth = 0; 156 } else if (xWidth > width) { 157 xWidth = width; 158 } 159 return xWidth; 160} 161