1// Copyright (c) 2021 Huawei Device Co., Ltd. 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14import { TraficEnum } from './utils/QueryEnum'; 15import { JanksStruct } from '../../bean/JanksStruct'; 16import { processFrameList } from './utils/AllMemoryCache'; 17import { Args } from './CommonArgs'; 18 19export const frameJankDataSql = (args: Args, configure: unknown): string => { 20 let timeLimit: string = ''; 21 let flag: string = ''; 22 let fsType: number = -1; 23 let fsFlag: string = ''; 24 //@ts-ignore 25 const endNS = args.endNS; 26 //@ts-ignore 27 const startNS = args.startNS; 28 //@ts-ignore 29 const recordStartNS = args.recordStartNS; 30 switch (configure) { 31 case 'ExepectMemory': 32 fsType = 1; 33 flag = 'fs.flag as jankTag,'; 34 break; 35 case 'ExpectedData': 36 fsType = 1; 37 flag = 'fs.flag as jankTag,'; 38 timeLimit = ` 39 AND (fs.ts - ${recordStartNS} + fs.dur) >= ${Math.floor(startNS)} 40 AND (fs.ts - ${recordStartNS}) <= ${Math.floor(endNS)}`; 41 break; 42 case 'ActualMemoryData': 43 fsType = 0; 44 flag = 45 '(case when (sf.flag == 1 or fs.flag == 1 ) then 1 when (sf.flag == 3 or fs.flag == 3 ) then 3 else 0 end) as jankTag,'; 46 fsFlag = 'AND fs.flag <> 2'; 47 break; 48 case 'ActualData': 49 fsType = 0; 50 flag = 51 '(case when (sf.flag == 1 or fs.flag == 1 ) then 1 when (sf.flag == 3 or fs.flag == 3 ) then 3 else 0 end) as jankTag,'; 52 fsFlag = 'AND fs.flag <> 2'; 53 timeLimit = `AND (fs.ts - ${recordStartNS} + fs.dur) >= ${Math.floor(startNS)} 54 AND (fs.ts - ${recordStartNS}) <= ${Math.floor(endNS)}`; 55 break; 56 default: 57 break; 58 } 59 let sql = setFrameJanksSql(args, timeLimit, flag, fsType, fsFlag); 60 return sql; 61}; 62function setFrameJanksSql(args: Args, timeLimit: string, flag: string, fsType: number, fsFlag: string): string { 63 //@ts-ignore 64 const recordStartNS = args.recordStartNS; 65 return `SELECT sf.id, 66 'frameTime' as frameType, 67 fs.ipid, 68 fs.vsync as name, 69 fs.dur as appDur, 70 (sf.ts + sf.dur - fs.ts) as dur, 71 (fs.ts - ${recordStartNS}) AS ts, 72 fs.type, 73 ${flag} 74 pro.pid, 75 pro.name as cmdline, 76 (sf.ts - ${recordStartNS}) AS rsTs, 77 sf.vsync AS rsVsync, 78 sf.dur AS rsDur, 79 sf.ipid AS rsIpid, 80 proc.pid AS rsPid, 81 proc.name AS rsName 82 FROM frame_slice AS fs 83 LEFT JOIN process AS pro ON pro.id = fs.ipid 84 LEFT JOIN frame_slice AS sf ON fs.dst = sf.id 85 LEFT JOIN process AS proc ON proc.id = sf.ipid 86 WHERE fs.dst IS NOT NULL 87 AND fs.type = ${fsType} 88 ${fsFlag} ${timeLimit} 89 UNION 90 SELECT -1 as id, 91 'frameTime' as frameType, 92 fs.ipid, 93 fs.vsync as name, 94 fs.dur as appDur, 95 fs.dur, 96 (fs.ts - ${recordStartNS}) AS ts, 97 fs.type, 98 fs.flag as jankTag, 99 pro.pid, 100 pro.name as cmdline, 101 NULL AS rsTs, NULL AS rsVsync, NULL AS rsDur, NULL AS rsIpid, NULL AS rsPid, NULL AS rsName 102 FROM frame_slice AS fs LEFT JOIN process AS pro ON pro.id = fs.ipid 103 WHERE fs.dst IS NULL 104 AND pro.name NOT LIKE '%render_service%' 105 AND fs.type = 1 106 ${fsFlag} ${timeLimit} 107 ORDER by ts`; 108} 109 110export function frameExpectedReceiver(data: unknown, proc: Function): void { 111 // @ts-ignore 112 if (data.params.trafic === TraficEnum.Memory) { 113 if (!processFrameList.has('FrameTimeLine_expected')) { 114 // @ts-ignore 115 let sql = frameJankDataSql(data.params, 'ExepectMemory'); 116 processFrameList.set('FrameTimeLine_expected', proc(sql)); 117 } 118 frameJanksReceiver(data, processFrameList.get('FrameTimeLine_expected')!, 'expected', true); 119 } else { 120 // @ts-ignore 121 let sql = frameJankDataSql(data.params, 'ExpectedData'); 122 let res = proc(sql); 123 // @ts-ignore 124 frameJanksReceiver(data, res, 'expect', data.params.trafic !== TraficEnum.SharedArrayBuffer); 125 } 126} 127 128export function frameActualReceiver(data: unknown, proc: Function): void { 129 // @ts-ignore 130 if (data.params.trafic === TraficEnum.Memory) { 131 if (!processFrameList.has('FrameTimeLine_actual')) { 132 // @ts-ignore 133 let sql = frameJankDataSql(data.params, 'ActualMemoryData'); 134 processFrameList.set('FrameTimeLine_actual', proc(sql)); 135 } 136 frameJanksReceiver(data, processFrameList.get('FrameTimeLine_actual')!, 'actual', true); 137 } else { 138 // @ts-ignore 139 let sql = frameJankDataSql(data.params, 'ActualData'); 140 let res = proc(sql); 141 // @ts-ignore 142 frameJanksReceiver(data, res, 'actual', data.params.trafic !== TraficEnum.SharedArrayBuffer); 143 } 144} 145let isIntersect = (leftData: JanksStruct, rightData: JanksStruct): boolean => 146 Math.max(leftData.ts! + leftData.dur!, rightData.ts! + rightData.dur!) - Math.min(leftData.ts!, rightData.ts!) < 147 leftData.dur! + rightData.dur!; 148function frameJanksReceiver(data: unknown, res: unknown[], type: string, transfer: boolean): void { 149 let frameJanks = new FrameJanks(data, transfer, res.length); 150 let unitIndex: number = 1; 151 let depths: unknown[] = []; 152 for (let index = 0; index < res.length; index++) { 153 let item = res[index]; 154 // @ts-ignore 155 data.params.trafic === TraficEnum.ProtoBuffer && (item = item.frameData); 156 // @ts-ignore 157 if (!item.dur || item.dur < 0) { 158 continue; 159 } 160 if (depths.length === 0) { 161 // @ts-ignore 162 item.depth = 0; 163 depths[0] = item; 164 } else { 165 let depthIndex: number = 0; 166 let isContinue: boolean = true; 167 while (isContinue) { 168 // @ts-ignore 169 if (isIntersect(depths[depthIndex], item)) { 170 if (depths[depthIndex + unitIndex] === undefined || !depths[depthIndex + unitIndex]) { 171 // @ts-ignore 172 item.depth = depthIndex + unitIndex; 173 depths[depthIndex + unitIndex] = item; 174 isContinue = false; 175 } 176 } else { 177 // @ts-ignore 178 item.depth = depthIndex; 179 depths[depthIndex] = item; 180 isContinue = false; 181 } 182 depthIndex++; 183 } 184 } 185 setFrameJanks(frameJanks, item, index); 186 } 187 postFrameJanksMessage(data, transfer, frameJanks, res.length); 188} 189function setFrameJanks(frameJanks: FrameJanks, itemData: unknown, index: number): void { 190 // @ts-ignore 191 frameJanks.id[index] = itemData.id; 192 // @ts-ignore 193 frameJanks.ipId[index] = itemData.ipid; 194 // @ts-ignore 195 frameJanks.name[index] = itemData.name; 196 // @ts-ignore 197 frameJanks.appDur[index] = itemData.appDur; 198 // @ts-ignore 199 frameJanks.dur[index] = itemData.dur; 200 // @ts-ignore 201 frameJanks.ts[index] = itemData.ts; 202 // @ts-ignore 203 frameJanks.jankTag[index] = itemData.jankTag ? itemData.jankTag : 0; 204 // @ts-ignore 205 frameJanks.pid[index] = itemData.pid; 206 // @ts-ignore 207 frameJanks.rsTs[index] = itemData.rsTs; 208 // @ts-ignore 209 frameJanks.rsVsync[index] = itemData.rsVsync; 210 // @ts-ignore 211 frameJanks.rsDur[index] = itemData.rsDur; 212 // @ts-ignore 213 frameJanks.rsIpId[index] = itemData.rsIpid; 214 // @ts-ignore 215 frameJanks.rsPid[index] = itemData.rsPid; 216 // @ts-ignore 217 frameJanks.rsName[index] = itemData.rsName; 218 // @ts-ignore 219 frameJanks.depth[index] = itemData.depth; 220} 221function setResults(transfer: boolean, frameJanks: FrameJanks): unknown { 222 return transfer 223 ? { 224 id: frameJanks.id.buffer, 225 ipid: frameJanks.ipId.buffer, 226 name: frameJanks.name.buffer, 227 app_dur: frameJanks.appDur.buffer, 228 dur: frameJanks.dur.buffer, 229 ts: frameJanks.ts.buffer, 230 jank_tag: frameJanks.jankTag.buffer, 231 pid: frameJanks.pid.buffer, 232 rs_ts: frameJanks.rsTs.buffer, 233 rs_vsync: frameJanks.rsVsync.buffer, 234 rs_dur: frameJanks.rsDur.buffer, 235 rs_ipid: frameJanks.rsIpId.buffer, 236 rs_pid: frameJanks.rsPid.buffer, 237 rs_name: frameJanks.rsName.buffer, 238 depth: frameJanks.depth.buffer, 239 } 240 : {}; 241} 242function postFrameJanksMessage(data: unknown, transfer: boolean, frameJanks: FrameJanks, len: number): void { 243 let results = setResults(transfer, frameJanks); 244 (self as unknown as Worker).postMessage( 245 { 246 // @ts-ignore 247 id: data.id, 248 // @ts-ignore 249 action: data.action, 250 results: results, 251 len: len, 252 transfer: transfer, 253 }, 254 transfer 255 ? [ 256 frameJanks.id.buffer, 257 frameJanks.ipId.buffer, 258 frameJanks.name.buffer, 259 frameJanks.appDur.buffer, 260 frameJanks.dur.buffer, 261 frameJanks.ts.buffer, 262 frameJanks.jankTag.buffer, 263 frameJanks.pid.buffer, 264 frameJanks.rsTs.buffer, 265 frameJanks.rsVsync.buffer, 266 frameJanks.rsDur.buffer, 267 frameJanks.rsIpId.buffer, 268 frameJanks.rsPid.buffer, 269 frameJanks.rsName.buffer, 270 frameJanks.depth.buffer, 271 ] 272 : [] 273 ); 274} 275class FrameJanks { 276 id: Uint16Array; 277 ipId: Uint16Array; 278 name: Int32Array; 279 appDur: Float64Array; 280 dur: Float64Array; 281 ts: Float64Array; 282 jankTag: Uint16Array; 283 pid: Uint16Array; 284 rsTs: Float64Array; 285 rsVsync: Int32Array; 286 rsDur: Float64Array; 287 rsIpId: Uint16Array; 288 rsPid: Uint16Array; 289 rsName: Int32Array; 290 depth: Uint16Array; 291 constructor(data: unknown, transfer: boolean, len: number) { 292 // @ts-ignore 293 this.id = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.id); 294 // @ts-ignore 295 this.ipId = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.ipid); 296 // @ts-ignore 297 this.name = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.name); 298 // @ts-ignore 299 this.appDur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.app_dur); 300 // @ts-ignore 301 this.dur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.dur); 302 // @ts-ignore 303 this.ts = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.ts); 304 // @ts-ignore 305 this.jankTag = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.jank_tag); 306 // @ts-ignore 307 this.pid = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.pid); 308 // @ts-ignore 309 this.rsTs = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.rs_ts); 310 // @ts-ignore 311 this.rsVsync = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.rs_vsync); 312 // @ts-ignore 313 this.rsDur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.rs_dur); 314 // @ts-ignore 315 this.rsIpId = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.rs_ipid); 316 // @ts-ignore 317 this.rsPid = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.rs_pid); 318 // @ts-ignore 319 this.rsName = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.rs_name); 320 // @ts-ignore 321 this.depth = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.depth); 322 } 323} 324