• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 { ColorUtils } from "../../component/trace/base/ColorUtils.js";
17import {
18    BaseStruct,
19    drawFlagLine,
20    drawLines,
21    drawLoading,
22    drawSelection, PerfRender,
23    RequestMessage
24} from "./ProcedureWorkerCommon.js";
25
26export class FileSystemRender extends PerfRender{
27    render(req: RequestMessage, list: Array<any>, filter: Array<any>,dataList2:Array<any>){
28        let groupBy10MS = req.scale > 20_000_000;
29        let isDiskIO :boolean = req.type!.includes("disk-io");
30        if(isDiskIO){
31            groupBy10MS = true;
32        }
33        if (req.lazyRefresh) {
34            fileSysChart(list, dataList2, req.type!, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, isDiskIO,req.useCache || !req.range.refresh);
35        } else {
36            if (!req.useCache) {
37                fileSysChart(list, dataList2, req.type!, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, isDiskIO,false);
38            }
39        }
40        let hoverStruct : FileSysChartStruct | undefined;
41        if (req.canvas) {
42            req.context.clearRect(0, 0, req.frame.width, req.frame.height);
43            let arr = filter;
44            if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) {
45                drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startNS, arr[arr.length - 1].startNS + arr[arr.length - 1].dur)
46            }
47            drawLines(req.context, req.xs, req.frame.height, req.lineColor)
48            req.context.stroke();
49            req.context.beginPath();
50            if (req.isHover) {
51                let offset = groupBy10MS ? 0 : 3;
52                for (let re of filter) {
53                    if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) {//&& req.hoverY >= re.frame.y && req.hoverY <= re.frame.y + re.frame.height
54                        hoverStruct = re;
55                        break;
56                    }
57                }
58            }
59            req.context.fillStyle = req.chartColor ?? ColorUtils.MD_PALETTE[0];
60            req.context.strokeStyle = req.chartColor ?? ColorUtils.MD_PALETTE[0];
61            let path = new Path2D();
62            for (let re of filter) {
63                FileSysChartStruct.draw(req.context, path, re, groupBy10MS);
64            }
65            req.context.fill(path);
66            drawSelection(req.context, req.params);
67            req.context.closePath();
68            drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS, req.frame, req.slicesTime);
69        }
70        let msg = {
71            id: req.id,
72            type: req.type,
73            results: req.canvas ? undefined : filter,
74            hover: hoverStruct
75        }
76        self.postMessage(msg);
77    }
78}
79
80export function fileSysChart(arr: Array<any>, arr2: any, type: string, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean, isDiskIO:boolean,use: boolean) {
81    if (use && res.length > 0 ) {//&& !groupBy10MS
82        let pns = (endNS - startNS) / frame.width;
83        let y = frame.y;
84        for (let i = 0; i < res.length; i++) {
85            let it = res[i];
86            if((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS){
87                if (!it.frame) {
88                    it.frame = {};
89                    it.frame.y = y;
90                }
91                it.frame.height = it.height;
92                FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame);
93            }else{
94                it.frame = null;
95            }
96        }
97        return;
98    }
99    res.length = 0;
100    if(arr){
101        let list: Array<any> = [];
102        let pns = (endNS - startNS) / frame.width;
103        let y = frame.y;
104        if(groupBy10MS){
105            if (arr2[type] && arr2[type].length > 0) {
106                list = arr2[type];
107            } else {
108                list = isDiskIO ? FileSysChartStruct.groupBy10MSWithMaxLatency(arr) : FileSysChartStruct.groupBy10MSWithCount(arr);
109                arr2[type] = list;
110            }
111            list = list.filter(it => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS);
112            let groups = list.map(it => {
113                if (!it.frame) {
114                    it.frame = {};
115                    it.frame.y = y;
116                }
117                it.frame.height = it.height;
118                FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame);
119                return it;
120            }).reduce((pre, current, index, arr) => {
121                (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current);
122                return pre;
123            }, {});
124            Reflect.ownKeys(groups).map((kv => {
125                // let arr = (groups[kv].sort((a: any, b: any) => b.frame.width - a.frame.width));
126                res.push(groups[kv][0]);
127            }));
128        }else{
129            let filter = arr.filter(it => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS);
130            list = FileSysChartStruct.computeHeightNoGroup(filter,totalNS);
131            list.map(it => {
132                if (!it.frame) {
133                    it.frame = {};
134                    it.frame.y = y;
135                }
136                it.frame.height = it.height;
137                FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame);
138                res.push(it);
139            })
140        }
141    }
142}
143
144export class FileSysChartStruct extends BaseStruct {
145    startNS: number | undefined;
146    endNS: number | undefined;
147    dur: number | undefined;
148    size: number | undefined;
149    height: number | undefined;
150    group10Ms: boolean | undefined;
151
152    static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: FileSysChartStruct, groupBy10MS: boolean) {
153        if (data.frame) {
154            let width = data.frame.width;
155            path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0)
156        }
157    }
158
159    static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) {
160        if ((node.startNS || 0) < startNS) {
161            node.frame.x = 0;
162        } else {
163            node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns);
164        }
165        if ((node.startNS || 0) + (node.dur || 0) > endNS) {
166            node.frame.width = frame.width - node.frame.x;
167        } else {
168            node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x);
169        }
170        if (node.frame.width < 1) {
171            node.frame.width = 1;
172        }
173    }
174
175    static computeHeightNoGroup(array:Array<any>,totalNS:number):Array<any>{
176        if(array.length > 0){
177            let time :Array<{time:number,type:number}> = [];
178            array.map((item) => {
179                time.push({time:item.startNS,type:1});
180                time.push({time:item.endNS || totalNS,type:-1});
181            })
182            time = time.sort((a,b) => a.time - b.time);
183            let arr:Array<any> = [];
184            let first = {
185                startNS: time[0].time ?? 0,
186                dur: 0,
187                size:1,
188                group10Ms:false,
189                height:1,
190            };
191            arr.push(first);
192            let max = 2
193            for (let i = 1,len = time.length; i < len; i++) {
194                let heap = {
195                    startNS: time[i].time,
196                    dur: 0,
197                    size:0,
198                    group10Ms:false,
199                    height: 0
200                };
201                arr[i - 1].dur = heap.startNS - arr[i - 1].startNS;
202                if (i == len - 1) {
203                    heap.dur = totalNS - heap.startNS;
204                }
205                heap.size = arr[i - 1].size + time[i].type;
206                heap.height = Math.floor(heap.size / 6 * 36);
207                max = max > heap.size ? max : heap.size;
208                arr.push(heap)
209            }
210            arr.map(it => it.height = Math.floor(it.size / max * 36))
211            return arr;
212        }else{
213            return [];
214        }
215    }
216
217    static groupBy10MSWithCount(array: Array<any>): Array<any> {
218        let obj = array.map(it => {
219            it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0;
220            return it;
221        }).reduce((pre, current) => {
222            (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current);
223            return pre;
224        }, {});
225        let arr: any[] = [];
226        let max = 1;
227        for (let aKey in obj) {
228            max = obj[aKey].length > max ? obj[aKey].length : max
229        }
230        for (let aKey in obj) {
231            let ns = parseInt(aKey);
232            let height: number = Math.floor(obj[aKey].length / max * 36);
233            arr.push({
234                startNS: ns,
235                dur: 1_000_000_0,
236                group10Ms:true,
237                size:obj[aKey].length,
238                height: height,
239            })
240        }
241        return arr;
242    }
243
244    static groupBy10MSWithMaxLatency(array: Array<any>): Array<any> {
245        let obj = array.map(it => {
246            it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0;
247            return it;
248        }).reduce((pre, current) => {
249            if(pre[current["timestamp_group"]] == undefined || pre[current["timestamp_group"]] == null){
250                pre[current["timestamp_group"]] = [];
251            }
252            if(pre[current["timestamp_group"]].length > 0){
253                let p = pre[current["timestamp_group"]][0];
254                if(p.dur < current.dur){
255                    pre[current["timestamp_group"]][0] = current;
256                }
257            }else{
258                pre[current["timestamp_group"]][0] = current;
259            }
260            return pre;
261        }, {});
262        let arr: any[] = [];
263        let max = 1;
264        for (let aKey in obj) {
265            max = obj[aKey][0].dur > max ? obj[aKey][0].dur : max
266        }
267        for (let aKey in obj) {
268            let ns = parseInt(aKey);
269            let height: number = Math.floor(obj[aKey][0].dur / max * 36);
270            arr.push({
271                startNS: ns,
272                dur: 1_000_000_0,
273                group10Ms:true,
274                size:obj[aKey][0].dur,
275                height: height,
276            })
277        }
278        return arr;
279    }
280}