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