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 condition: 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 condition = 'AND t.tid = pro.pid'; 35 break; 36 case 'ExpectedData': 37 fsType = 1; 38 flag = 'fs.flag as jankTag,'; 39 condition = ` 40 AND (fs.ts - ${recordStartNS} + fs.dur) >= ${Math.floor(startNS)} 41 AND (fs.ts - ${recordStartNS}) <= ${Math.floor(endNS)}`; 42 break; 43 case 'ActualMemoryData': 44 fsType = 0; 45 flag = 46 '(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,'; 47 fsFlag = 'AND fs.flag <> 2'; 48 break; 49 case 'ActualData': 50 fsType = 0; 51 flag = 52 '(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,'; 53 fsFlag = 'AND fs.flag <> 2'; 54 condition = `AND (fs.ts - ${recordStartNS} + fs.dur) >= ${Math.floor(startNS)} 55 AND (fs.ts - ${recordStartNS}) <= ${Math.floor(endNS)}`; 56 break; 57 default: 58 break; 59 } 60 let sql = setFrameJanksSql(args, condition, flag, fsType, fsFlag); 61 return sql; 62}; 63function setFrameJanksSql(args: Args, timeLimit: string, flag: string, fsType: number, fsFlag: string): string { 64 //@ts-ignore 65 const recordStartNS = args.recordStartNS; 66 return `SELECT sf.id, 67 'frameTime' as frameType, 68 fs.ipid, 69 fs.vsync as name, 70 fs.dur as appDur, 71 (sf.ts + sf.dur - fs.ts) as dur, 72 (fs.ts - ${recordStartNS}) AS ts, 73 fs.type, 74 ${flag} 75 pro.pid, 76 t.tid, 77 pro.name as cmdline, 78 (sf.ts - ${recordStartNS}) AS rsTs, 79 sf.vsync AS rsVsync, 80 sf.dur AS rsDur, 81 sf.ipid AS rsIpid, 82 proc.pid AS rsPid, 83 proc.name AS rsName 84 FROM frame_slice AS fs 85 LEFT JOIN process AS pro ON pro.id = fs.ipid 86 LEFT JOIN frame_slice AS sf ON fs.dst = sf.id 87 LEFT JOIN process AS proc ON proc.id = sf.ipid 88 LEFT JOIN thread as t on fs.itid = t.id 89 WHERE fs.dst IS NOT NULL 90 AND fs.type = ${fsType} 91 ${fsFlag} ${timeLimit} 92 UNION 93 SELECT -1 as id, 94 'frameTime' as frameType, 95 fs.ipid, 96 fs.vsync as name, 97 fs.dur as appDur, 98 fs.dur, 99 (fs.ts - ${recordStartNS}) AS ts, 100 fs.type, 101 fs.flag as jankTag, 102 pro.pid, 103 t.tid, 104 pro.name as cmdline, 105 NULL AS rsTs, NULL AS rsVsync, NULL AS rsDur, NULL AS rsIpid, NULL AS rsPid, NULL AS rsName 106 FROM frame_slice AS fs LEFT JOIN process AS pro ON pro.id = fs.ipid 107 LEFT JOIN thread as t on fs.itid = t.id 108 WHERE fs.dst IS NULL 109 AND pro.name NOT LIKE '%render_service%' 110 AND fs.type = 1 111 ${fsFlag} ${timeLimit} 112 ORDER by ts`; 113} 114 115export function frameExpectedReceiver(data: unknown, proc: Function): void { 116 // @ts-ignore 117 if (data.params.trafic === TraficEnum.Memory) { 118 if (!processFrameList.has('FrameTimeLine_expected')) { 119 // @ts-ignore 120 let sql = frameJankDataSql(data.params, 'ExepectMemory'); 121 processFrameList.set('FrameTimeLine_expected', proc(sql)); 122 } 123 frameJanksReceiver(data, processFrameList.get('FrameTimeLine_expected')!, 'expected', true); 124 } else { 125 // @ts-ignore 126 let sql = frameJankDataSql(data.params, 'ExpectedData'); 127 let res = proc(sql); 128 // @ts-ignore 129 frameJanksReceiver(data, res, 'expect', data.params.trafic !== TraficEnum.SharedArrayBuffer); 130 } 131} 132 133export function frameActualReceiver(data: unknown, proc: Function): void { 134 // @ts-ignore 135 if (data.params.trafic === TraficEnum.Memory) { 136 if (!processFrameList.has('FrameTimeLine_actual')) { 137 // @ts-ignore 138 let sql = frameJankDataSql(data.params, 'ActualMemoryData'); 139 processFrameList.set('FrameTimeLine_actual', proc(sql)); 140 } 141 frameJanksReceiver(data, processFrameList.get('FrameTimeLine_actual')!, 'actual', true); 142 } else { 143 // @ts-ignore 144 let sql = frameJankDataSql(data.params, 'ActualData'); 145 let res = proc(sql); 146 // @ts-ignore 147 frameJanksReceiver(data, res, 'actual', data.params.trafic !== TraficEnum.SharedArrayBuffer); 148 } 149} 150let isIntersect = (leftData: JanksStruct, rightData: JanksStruct): boolean => 151 Math.max(leftData.ts! + leftData.dur!, rightData.ts! + rightData.dur!) - Math.min(leftData.ts!, rightData.ts!) < 152 leftData.dur! + rightData.dur!; 153function frameJanksReceiver(data: unknown, res: unknown[], type: string, transfer: boolean): void { 154 let frameJanks = new FrameJanks(data, transfer, res.length); 155 let unitIndex: number = 1; 156 let depths: unknown[] = []; 157 for (let index = 0; index < res.length; index++) { 158 let item = res[index]; 159 // @ts-ignore 160 data.params.trafic === TraficEnum.ProtoBuffer && (item = item.frameData); 161 // @ts-ignore 162 if (!item.dur || item.dur < 0) { 163 continue; 164 } 165 if (depths.length === 0) { 166 // @ts-ignore 167 item.depth = 0; 168 depths[0] = item; 169 } else { 170 let depthIndex: number = 0; 171 let isContinue: boolean = true; 172 while (isContinue) { 173 // @ts-ignore 174 if (isIntersect(depths[depthIndex], item)) { 175 if (depths[depthIndex + unitIndex] === undefined || !depths[depthIndex + unitIndex]) { 176 // @ts-ignore 177 item.depth = depthIndex + unitIndex; 178 depths[depthIndex + unitIndex] = item; 179 isContinue = false; 180 } 181 } else { 182 // @ts-ignore 183 item.depth = depthIndex; 184 depths[depthIndex] = item; 185 isContinue = false; 186 } 187 depthIndex++; 188 } 189 } 190 setFrameJanks(frameJanks, item, index); 191 } 192 postFrameJanksMessage(data, transfer, frameJanks, res.length); 193} 194function setFrameJanks(frameJanks: FrameJanks, itemData: unknown, index: number): void { 195 // @ts-ignore 196 frameJanks.id[index] = itemData.id; 197 // @ts-ignore 198 frameJanks.ipId[index] = itemData.ipid; 199 // @ts-ignore 200 frameJanks.name[index] = itemData.name; 201 // @ts-ignore 202 frameJanks.appDur[index] = itemData.appDur; 203 // @ts-ignore 204 frameJanks.dur[index] = itemData.dur; 205 // @ts-ignore 206 frameJanks.ts[index] = itemData.ts; 207 // @ts-ignore 208 frameJanks.jankTag[index] = itemData.jankTag ? itemData.jankTag : 0; 209 // @ts-ignore 210 frameJanks.pid[index] = itemData.pid; 211 // @ts-ignore 212 frameJanks.tid[index] = itemData.tid; 213 // @ts-ignore 214 frameJanks.rsTs[index] = itemData.rsTs; 215 // @ts-ignore 216 frameJanks.rsVsync[index] = itemData.rsVsync; 217 // @ts-ignore 218 frameJanks.rsDur[index] = itemData.rsDur; 219 // @ts-ignore 220 frameJanks.rsIpId[index] = itemData.rsIpid; 221 // @ts-ignore 222 frameJanks.rsPid[index] = itemData.rsPid; 223 // @ts-ignore 224 frameJanks.rsName[index] = itemData.rsName; 225 // @ts-ignore 226 frameJanks.depth[index] = itemData.depth; 227} 228function setResults(transfer: boolean, frameJanks: FrameJanks): unknown { 229 return transfer 230 ? { 231 id: frameJanks.id.buffer, 232 ipid: frameJanks.ipId.buffer, 233 name: frameJanks.name.buffer, 234 app_dur: frameJanks.appDur.buffer, 235 dur: frameJanks.dur.buffer, 236 ts: frameJanks.ts.buffer, 237 jank_tag: frameJanks.jankTag.buffer, 238 pid: frameJanks.pid.buffer, 239 tid: frameJanks.tid.buffer, 240 rs_ts: frameJanks.rsTs.buffer, 241 rs_vsync: frameJanks.rsVsync.buffer, 242 rs_dur: frameJanks.rsDur.buffer, 243 rs_ipid: frameJanks.rsIpId.buffer, 244 rs_pid: frameJanks.rsPid.buffer, 245 rs_name: frameJanks.rsName.buffer, 246 depth: frameJanks.depth.buffer, 247 } 248 : {}; 249} 250function postFrameJanksMessage(data: unknown, transfer: boolean, frameJanks: FrameJanks, len: number): void { 251 let results = setResults(transfer, frameJanks); 252 (self as unknown as Worker).postMessage( 253 { 254 // @ts-ignore 255 id: data.id, 256 // @ts-ignore 257 action: data.action, 258 results: results, 259 len: len, 260 transfer: transfer, 261 }, 262 transfer 263 ? [ 264 frameJanks.id.buffer, 265 frameJanks.ipId.buffer, 266 frameJanks.name.buffer, 267 frameJanks.appDur.buffer, 268 frameJanks.dur.buffer, 269 frameJanks.ts.buffer, 270 frameJanks.jankTag.buffer, 271 frameJanks.pid.buffer, 272 frameJanks.tid.buffer, 273 frameJanks.rsTs.buffer, 274 frameJanks.rsVsync.buffer, 275 frameJanks.rsDur.buffer, 276 frameJanks.rsIpId.buffer, 277 frameJanks.rsPid.buffer, 278 frameJanks.rsName.buffer, 279 frameJanks.depth.buffer, 280 ] 281 : [] 282 ); 283} 284class FrameJanks { 285 id: Uint16Array; 286 ipId: Uint16Array; 287 name: Int32Array; 288 appDur: Float64Array; 289 dur: Float64Array; 290 ts: Float64Array; 291 jankTag: Uint16Array; 292 pid: Uint32Array; 293 tid: Uint32Array; 294 rsTs: Float64Array; 295 rsVsync: Int32Array; 296 rsDur: Float64Array; 297 rsIpId: Uint16Array; 298 rsPid: Uint32Array; 299 rsName: Int32Array; 300 depth: Uint16Array; 301 constructor(data: unknown, transfer: boolean, len: number) { 302 // @ts-ignore 303 this.id = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.id); 304 // @ts-ignore 305 this.ipId = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.ipid); 306 // @ts-ignore 307 this.name = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.name); 308 // @ts-ignore 309 this.appDur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.app_dur); 310 // @ts-ignore 311 this.dur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.dur); 312 // @ts-ignore 313 this.ts = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.ts); 314 // @ts-ignore 315 this.jankTag = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.jank_tag); 316 // @ts-ignore 317 this.pid = new Uint32Array(transfer ? len : data.params.sharedArrayBuffers.pid); 318 // @ts-ignore 319 this.tid = new Uint32Array(transfer ? len : data.params.sharedArrayBuffers.tid); 320 // @ts-ignore 321 this.rsTs = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.rs_ts); 322 // @ts-ignore 323 this.rsVsync = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.rs_vsync); 324 // @ts-ignore 325 this.rsDur = new Float64Array(transfer ? len : data.params.sharedArrayBuffers.rs_dur); 326 // @ts-ignore 327 this.rsIpId = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.rs_ipid); 328 // @ts-ignore 329 this.rsPid = new Uint32Array(transfer ? len : data.params.sharedArrayBuffers.rs_pid); 330 // @ts-ignore 331 this.rsName = new Int32Array(transfer ? len : data.params.sharedArrayBuffers.rs_name); 332 // @ts-ignore 333 this.depth = new Uint16Array(transfer ? len : data.params.sharedArrayBuffers.depth); 334 } 335} 336