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 { BaseElement, element } from '../../../../../base-ui/BaseElement'; 17import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; 18import { LitTable } from '../../../../../base-ui/table/lit-table'; 19import { JankFramesStruct } from '../../../../bean/JankFramesStruct'; 20import { JanksStruct } from '../../../../bean/JanksStruct'; 21import { resizeObserver } from '../SheetUtils'; 22import { querySelectRangeData } from '../../../../database/sql/Janks.sql'; 23 24@element('tabpane-frames') 25export class TabPaneFrames extends BaseElement { 26 private framesTbl: LitTable | null | undefined; 27 private range: HTMLLabelElement | null | undefined; 28 private framesSource: Array<unknown> = []; 29 set data(framesParam: SelectionParam | unknown) { 30 this.range!.textContent = // @ts-ignore 31 'Selected range: ' + parseFloat(((framesParam.rightNs - framesParam.leftNs) / 1000000.0).toFixed(5)) + ' ms'; 32 this.queryDataByDB(framesParam); 33 } 34 35 queryDataByDB(framesParam: SelectionParam | unknown): void { 36 let tablelist = new Array<JankFramesStruct>(); 37 let sumRes: JankFramesStruct = new JankFramesStruct(); 38 let appJank: JankFramesStruct = new JankFramesStruct(); 39 let rsJank: JankFramesStruct = new JankFramesStruct(); 40 let noJank: JankFramesStruct = new JankFramesStruct(); // @ts-ignore 41 if (framesParam.jankFramesData.length > 0) { 42 let allPid: Array<number> = []; 43 let allData: Array<unknown> = []; // @ts-ignore 44 framesParam.jankFramesData.forEach((data: unknown) => { 45 if (typeof data === 'string') { 46 if (Number(data) && allPid.indexOf(Number(data)) < 0) { 47 allPid.push(Number(data)); 48 } 49 } else { 50 allData.push(data); 51 } 52 }); // @ts-ignore 53 querySelectRangeData(allPid, framesParam.leftNs, framesParam.rightNs).then((result: unknown) => { 54 // @ts-ignore 55 sumRes.occurrences = allData.length + result.length; 56 allData.forEach((item) => { 57 // frameTime 58 // @ts-ignore 59 this.frameTimelineJankDataHandle(item, appJank, noJank); 60 }); // @ts-ignore 61 result.forEach((structValue: JanksStruct) => { 62 if (structValue.frameType === 'app') { 63 this.appJankDataHandle(structValue, appJank, noJank); 64 } else if (structValue.frameType === 'render_service') { 65 this.rsJankDataHandle(structValue, rsJank, noJank); 66 } 67 }); 68 tablelist.push(sumRes); 69 tablelist = this.setFrameDataDur(appJank, rsJank, noJank, tablelist); 70 this.framesSource = tablelist; 71 this.framesTbl!.recycleDataSource = tablelist; 72 }); 73 } 74 } 75 76 private setFrameDataDur( 77 appFrame: JankFramesStruct, 78 rsFrame: JankFramesStruct, 79 noFrame: JankFramesStruct, 80 tableList: JankFramesStruct[] 81 ): JankFramesStruct[] { 82 if (appFrame.occurrences > 0) { 83 appFrame.maxDurationStr = appFrame.maxDuration + ''; 84 appFrame.minDurationStr = appFrame.minDuration + ''; 85 appFrame.meanDurationStr = appFrame.meanDuration + ''; 86 tableList.push(appFrame); 87 } 88 if (rsFrame.occurrences > 0) { 89 rsFrame.maxDurationStr = rsFrame.maxDuration + ''; 90 rsFrame.minDurationStr = rsFrame.minDuration + ''; 91 rsFrame.meanDurationStr = rsFrame.meanDuration + ''; 92 tableList.push(rsFrame); 93 } 94 if (noFrame.occurrences > 0) { 95 noFrame.maxDurationStr = noFrame.maxDuration + ''; 96 noFrame.minDurationStr = noFrame.minDuration + ''; 97 noFrame.meanDurationStr = noFrame.meanDuration + ''; 98 tableList.push(noFrame); 99 } 100 return tableList; 101 } 102 103 private frameTimelineJankDataHandle( 104 structValue: JanksStruct, 105 appJank: JankFramesStruct, 106 noJank: JankFramesStruct 107 ): void { 108 if (structValue.dur === null || structValue.dur === undefined) { 109 structValue.dur = 0; 110 } 111 if (structValue && structValue.jank_tag && structValue.jank_tag > 0) { 112 appJank.flag = structValue.jank_tag; 113 appJank.jankType = 'Deadline Missed'; 114 appJank.occurrences += 1; 115 appJank.maxDuration = Math.max(structValue.dur, appJank.maxDuration); 116 appJank.minDuration = Math.min(structValue.dur, appJank.minDuration); 117 if (appJank.minDuration === -1) { 118 appJank.minDuration = structValue.dur; 119 } else { 120 appJank.minDuration = Math.min(structValue.dur, appJank.minDuration!); 121 } 122 if (appJank.meanDuration === -1) { 123 appJank.meanDuration = structValue.dur; 124 } else { 125 appJank.meanDuration = Number(((structValue.dur + appJank.meanDuration) / 2).toFixed(2)); 126 } 127 } else { 128 noJank.flag = structValue.jank_tag; 129 noJank.jankType = 'None'; 130 noJank.occurrences += 1; 131 noJank.maxDuration = Math.max(structValue.dur, noJank.maxDuration); 132 if (noJank.minDuration === -1) { 133 noJank.minDuration = structValue.dur; 134 } else { 135 noJank.minDuration = Math.min(structValue.dur, noJank.minDuration!); 136 } 137 if (noJank.meanDuration === -1) { 138 noJank.meanDuration = structValue.dur; 139 } else { 140 noJank.meanDuration = Number(((structValue.dur + noJank.meanDuration) / 2).toFixed(2)); 141 } 142 } 143 } 144 private rsJankDataHandle(structValue: JanksStruct, rsJank: JankFramesStruct, noJank: JankFramesStruct): void { 145 if (structValue.dur === null || structValue.dur === undefined) { 146 structValue.dur = 0; 147 } 148 if (structValue.jank_tag && structValue.jank_tag > 0) { 149 rsJank.flag = structValue.jank_tag; 150 rsJank.jankType = 'RenderService Deadline Missed'; 151 rsJank.occurrences += 1; 152 rsJank.maxDuration = Math.max(structValue.dur, rsJank.maxDuration!); 153 if (rsJank.minDuration === -1) { 154 rsJank.minDuration = structValue.dur; 155 } else { 156 rsJank.minDuration = Math.min(structValue.dur, rsJank.minDuration!); 157 } 158 if (rsJank.meanDuration === -1) { 159 rsJank.meanDuration = structValue.dur; 160 } else { 161 rsJank.meanDuration = Number(((structValue.dur + rsJank.meanDuration!) / 2).toFixed(2)); 162 } 163 } else { 164 this.refreshNoJankData(noJank, structValue); 165 } 166 } 167 private appJankDataHandle(structValue: JanksStruct, appJank: JankFramesStruct, noJank: JankFramesStruct): void { 168 if (structValue.dur === null || structValue.dur === undefined) { 169 structValue.dur = 0; 170 } 171 if (structValue.jank_tag && structValue.jank_tag > 0) { 172 appJank.flag = structValue.jank_tag; 173 appJank.jankType = 'APP Deadline Missed'; 174 appJank.occurrences += 1; 175 appJank.maxDuration = Math.max(structValue.dur, appJank.maxDuration!); 176 if (appJank.minDuration === -1) { 177 appJank.minDuration = structValue.dur; 178 } else { 179 appJank.minDuration = Math.min(structValue.dur, appJank.minDuration!); 180 } 181 if (appJank.meanDuration === -1) { 182 appJank.meanDuration = structValue.dur; 183 } else { 184 appJank.meanDuration = Number(((structValue.dur + appJank.meanDuration!) / 2).toFixed(2)); 185 } 186 } else { 187 this.refreshNoJankData(noJank, structValue); 188 } 189 } 190 private refreshNoJankData(noJank: JankFramesStruct, structValue: JanksStruct): void { 191 noJank.flag = structValue.jank_tag; 192 noJank.jankType = 'None'; 193 noJank.occurrences += 1; 194 noJank.maxDuration = Math.max(structValue.dur!, noJank.maxDuration!); 195 if (noJank.minDuration === -1) { 196 noJank.minDuration = structValue.dur!; 197 } else { 198 noJank.minDuration = Math.min(structValue.dur!, noJank.minDuration!); 199 } 200 if (noJank.meanDuration === -1) { 201 noJank.meanDuration = structValue.dur!; 202 } else { 203 noJank.meanDuration = Number(((structValue.dur! + noJank.meanDuration!) / 2).toFixed(2)); 204 } 205 } 206 207 initElements(): void { 208 this.framesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-frames'); 209 this.range = this.shadowRoot?.querySelector('#jank-frames-time-range'); 210 this.framesTbl!.addEventListener('column-click', (evt) => { 211 // @ts-ignore 212 this.sortByColumn(evt.detail); 213 }); 214 } 215 216 connectedCallback(): void { 217 super.connectedCallback(); 218 resizeObserver(this.parentElement!, this.framesTbl!); 219 } 220 221 initHtml(): string { 222 return ` 223 <style> 224 .frames-label{ 225 height: 20px; 226 text-align: end; 227 } 228 :host{ 229 padding: 10px 10px; 230 display: flex; 231 flex-direction: column; 232 } 233 </style> 234 <label id="jank-frames-time-range" class="frames-label" style="width: 100%;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label> 235 <lit-table id="tb-frames" style="height: auto"> 236 <lit-table-column class="jank-frames-column" title="Jank Type" width="1fr" data-index="jankType" key="jankType" align="flex-start" order> 237 </lit-table-column> 238 <lit-table-column class="jank-frames-column" title="Min duration" width="1fr" data-index="minDurationStr" key="minDurationStr" align="flex-start" order > 239 </lit-table-column> 240 <lit-table-column class="jank-frames-column" title="Max duration" width="1fr" data-index="maxDurationStr" key="maxDurationStr" align="flex-start" order > 241 </lit-table-column> 242 <lit-table-column class="jank-frames-column" title="Mean duration" width="1fr" data-index="meanDurationStr" key="meanDurationStr" align="flex-start" order > 243 </lit-table-column> 244 <lit-table-column class="jank-frames-column" title="Occurrences" width="1fr" data-index="occurrences" key="occurrences" align="flex-start" order > 245 </lit-table-column> 246 </lit-table> 247 `; 248 } 249 250 sortByColumn(framesDetail: unknown): void { 251 // @ts-ignore 252 function compare(property, sort, type) { 253 return function (framesLeftData: SelectionData, framesRightData: SelectionData) { 254 if (framesLeftData.process === ' ' || framesRightData.process === ' ') { 255 return 0; 256 } 257 if (type === 'number') { 258 return sort === 2 259 ? // @ts-ignore 260 parseFloat(framesRightData[property]) - parseFloat(framesLeftData[property]) 261 : // @ts-ignore 262 parseFloat(framesLeftData[property]) - parseFloat(framesRightData[property]); 263 } else { 264 // @ts-ignore 265 if (framesRightData[property] > framesLeftData[property]) { 266 return sort === 2 ? 1 : -1; 267 } else { 268 // @ts-ignore 269 if (framesRightData[property] === framesLeftData[property]) { 270 return 0; 271 } else { 272 return sort === 2 ? -1 : 1; 273 } 274 } 275 } 276 }; 277 } 278 279 // @ts-ignore 280 if (framesDetail.key === 'jankType') { 281 // @ts-ignore 282 this.framesSource.sort(compare(framesDetail.key, framesDetail.sort, 'string')); 283 } else { 284 // @ts-ignore 285 this.framesSource.sort(compare(framesDetail.key, framesDetail.sort, 'number')); 286 } 287 this.framesTbl!.recycleDataSource = this.framesSource; 288 } 289} 290