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 { BaseStruct, Rect, drawLoadingFrame, isFrameContainPoint } from './ProcedureWorkerCommon'; 16import { TraceRow } from '../../component/trace/base/TraceRow'; 17import { HeapSample } from '../../../js-heap/model/DatabaseStruct'; 18 19export class HeapTimelineRender { 20 renderMainThread( 21 req: { 22 context: CanvasRenderingContext2D; 23 useCache: boolean; 24 type: string; 25 samples: Array<HeapSample>; 26 }, 27 row: TraceRow<HeapTimelineStruct> 28 ) { 29 let list = row.dataListCache; 30 let filter: Array<any> = []; 31 if (list.length === 0) { 32 return; 33 } 34 HeapTimelineStruct.samples = req.samples; 35 HeapTimeline( 36 list, 37 filter, 38 HeapTimelineStruct.samples, 39 TraceRow.range?.startNS ?? 0, 40 TraceRow.range?.endNS ?? 0, 41 (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), 42 row.frame 43 ); 44 drawLoadingFrame(req.context, filter, row); 45 let heapTimelineFind = false; 46 for (let re of filter) { 47 HeapTimelineStruct.draw(req.context, re); 48 this.setHoverStruct(row, re, heapTimelineFind); 49 } 50 if (!heapTimelineFind && row.isHover) { 51 HeapTimelineStruct.hoverHeapTimelineStruct = undefined; 52 } 53 } 54 setHoverStruct(row: TraceRow<HeapTimelineStruct>, re: HeapTimelineStruct, heapTimelineFind: boolean) { 55 if (row.isHover) { 56 if (re.size === 0) { 57 if ( 58 re.frame && 59 row.hoverX >= re.frame.x && 60 row.hoverX <= re.frame.x && 61 row.hoverY >= re.frame.y && 62 row.hoverY <= re.frame.y + re.frame.height 63 ) { 64 HeapTimelineStruct.hoverHeapTimelineStruct = re; 65 heapTimelineFind = true; 66 } 67 } else { 68 if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 69 HeapTimelineStruct.hoverHeapTimelineStruct = re; 70 heapTimelineFind = true; 71 } 72 } 73 } 74 } 75} 76export function HeapTimeline( 77 list: Array<any>, 78 filter: Array<any>, 79 samples: Array<HeapSample>, 80 startNS: number, 81 endNS: number, 82 totalNS: number, 83 frame: any 84) { 85 let maxSize = 0; 86 let index = []; 87 for (let i = 1; i < samples.length; i++) { 88 if (samples[i].size > 0) { 89 maxSize = Math.max(maxSize, samples[i].size); 90 index.push(i); 91 } 92 } 93 filter.length = 0; 94 for (let i of index) { 95 HeapTimelineStruct.setFrame( 96 samples[i].timestamp, 97 samples[i].size, 98 maxSize, 99 list[i], 100 startNS || 0, 101 endNS || 0, 102 totalNS || 0, 103 frame 104 ); 105 } 106 for (let i = 0, len = list.length; i < len; i++) { 107 if (list[i].frame) { 108 filter.push(list[i]); 109 } 110 } 111} 112export class HeapTimelineStruct extends BaseStruct { 113 static hoverHeapTimelineStruct: HeapTimelineStruct | undefined; 114 static samples: Array<HeapSample>; 115 size: number = 0; 116 117 static setFrame( 118 timestamp: number, 119 size: number, 120 maxSize: number, 121 node: any, 122 startNS: number, 123 endNS: number, 124 totalNS: number, 125 frame: Rect 126 ) { 127 node.frame = null; 128 // us * 1000 = ns 129 if (node.timestamp * 1000 > startNS && node.timestamp * 1000 < endNS && node.timestamp === timestamp) { 130 let rectangle: Rect = new Rect( 131 Math.floor(((timestamp * 1000 - startNS) / totalNS) * frame.width), 132 0, 133 2, 134 Math.floor((size / maxSize) * frame.height) < 1 ? 1 : Math.floor((size / maxSize) * frame.height) 135 ); 136 node.frame = rectangle; 137 } 138 } 139 140 static draw(ctx: CanvasRenderingContext2D, node: HeapTimelineStruct): void { 141 ctx!.beginPath(); 142 ctx!.lineWidth = 2; 143 ctx!.strokeStyle = '#0A59F7'; 144 ctx!.moveTo(node.frame!.x, 40); 145 ctx!.lineTo(node.frame!.x, 40 - node.frame!.height); 146 ctx!.stroke(); 147 ctx!.closePath(); 148 } 149} 150