• 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 {
17    BaseStruct,
18    drawFlagLine, drawLines,
19    drawLoading,
20    drawSelection,
21    ns2x,
22    Render,
23    RequestMessage
24} from "./ProcedureWorkerCommon.js";
25
26export class EnergyPowerRender extends Render {
27    render(req: RequestMessage, list: Array<any>, filter: Array<any>) {
28        if (req.lazyRefresh) {
29            power(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache
30                || !req.range.refresh, req.params.maxPowerName);
31        } else {
32            if (!req.useCache) {
33                power(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false, req.params.maxPowerName);
34            }
35        }
36        if (req.canvas) {
37            req.context.clearRect(0, 0, req.canvas.width, EnergyPowerStruct.rowHeight);
38            let arr = filter;
39            if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) {
40                drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startNS,
41                    arr[arr.length - 1].startNS + arr[arr.length - 1].dur)
42            }
43            drawLines(req.context, req.xs, req.frame.height, req.lineColor)
44            req.context.beginPath();
45            EnergyPowerStruct.hoverEnergyPowerStruct = undefined;
46            if (req.isHover) {
47                for (let re of filter) {
48                    if (re.frame && req.hoverX >= re.frame.x && req.hoverX <= re.frame.x + re.frame.width && req.hoverY >= re.frame.y && req.hoverY <= re.frame.y + re.frame.height) {
49                        EnergyPowerStruct.hoverEnergyPowerStruct = re;
50                        break;
51                    }
52                }
53            }
54            EnergyPowerStruct.selectEnergyPowerStruct = req.params.selectEnergyPowerStruct;
55            for (let index = 0; index < filter.length; index++) {
56                EnergyPowerStruct.draw(req, index, filter[index])
57            }
58            req.context.stroke();
59            drawSelection(req.context, req.params);
60            req.context.closePath();
61            if (EnergyPowerStruct.maxPower != 0) {
62                let s = EnergyPowerStruct.maxPower.toString()
63                let textMetrics = req.context.measureText(s);
64                req.context.globalAlpha = 1.0
65                req.context.fillStyle = "#f0f0f0"
66                req.context.fillRect(0, 5, textMetrics.width + 8, 18)
67                req.context.globalAlpha = 1
68                req.context.fillStyle = "#333"
69                req.context.textBaseline = "middle"
70                req.context.fillText(s, 4, 5 + 9)
71            }
72            drawLegend(req)
73            drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS,
74                req.frame, req.slicesTime);
75        }
76        // @ts-ignore
77        self.postMessage({
78            id: req.id,
79            type: req.type,
80            results: req.canvas ? undefined : filter,
81            hover: EnergyPowerStruct.hoverEnergyPowerStruct
82        });
83    }
84}
85
86export function drawLegend(req: RequestMessage){
87    let textList = ["CPU", "LOCATION", "GPU", "DISPLAY", "CAMERA", "BLUETOOTH", "FLASHLIGHT", "AUDIO", "WIFISCAN"]
88    for (let index = 0; index < textList.length; index++) {
89        let text = req.context.measureText(textList[index]);
90        req.context.fillStyle = EnergyPowerStruct.getHistogramColor(textList[index]);
91        req.context.globalAlpha = 1
92        if(index == 0){
93            req!.context.fillRect(req.canvas.width - (EnergyPowerStruct.powerItemNumber * 80), 12, 8, 8);
94            req.context.globalAlpha = 1
95            req.context.fillStyle = "#333"
96            req.context.textBaseline = "middle"
97            req.context.fillText(textList[index], req.canvas.width - (EnergyPowerStruct.powerItemNumber * 80) + 10, 18)
98            EnergyPowerStruct.currentTextWidth = req.canvas.width - (EnergyPowerStruct.powerItemNumber * 80) + 40 + text.width
99        } else {
100            req!.context.fillRect(EnergyPowerStruct.currentTextWidth, 12, 8, 8);
101            req.context.globalAlpha = 1
102            req.context.fillStyle = "#333"
103            req.context.textBaseline = "middle"
104            req!.context.fillText(textList[index], EnergyPowerStruct.currentTextWidth + 12, 18);
105            EnergyPowerStruct.currentTextWidth = EnergyPowerStruct.currentTextWidth + 40 + text.width
106        }
107    }
108}
109
110export function power(list: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number,
111                      frame: any, use: boolean, appName: string) {
112    if (use && res.length > 0) {
113        for (let i = 0; i < res.length; i++) {
114            let item = res[i];
115            let obj = item[appName]
116            if (obj != undefined) {
117                if ((obj.ts + 1000000000) > (startNS || 0) && (obj.ts || 0) < (endNS || 0)) {
118                    EnergyPowerStruct.setPowerFrame(item, 5, startNS || 0, endNS || 0,
119                        totalNS || 0, frame)
120                } else {
121                    obj.frame = null;
122                }
123            }
124        }
125        return;
126    }
127    res.length = 0;
128    if (list) {
129        let firstList: Array<any> = []
130        EnergyPowerStruct.maxPower = 0
131        for (let index = 0; index < list.length; index++) {
132            let item = list[index];
133            let obj = item[appName]
134            if (obj != undefined) {
135                if ((obj.ts + 1000000000) > (startNS || 0) && (obj.ts || 0) < (endNS || 0)) {
136                    firstList.push(obj)
137                }
138            }
139        }
140
141        let array = firstList.sort((a, b) => a.ts - b.ts);
142        for (let index = 0; index < array.length; index++) {
143            if (res.length == 0) {
144                res.push(array[index])
145            } else {
146                let rightTime = array[index].ts + 500000000;
147                let leftTime = array[index].ts - 500000000;
148                let obj = res[res.length - 1];
149                if (obj.ts >= leftTime && obj.ts <= rightTime) {
150                    obj.cpu = obj.cpu == 0 ? array[index].cpu : obj.cpu
151                    obj.location = obj.location == 0 ? array[index].location : obj.location
152                    obj.gpu = obj.gpu == 0 ? array[index].gpu : obj.gpu
153                    obj.display = obj.display == 0 ? array[index].display : obj.display
154                    obj.camera = obj.camera == 0 ? array[index].camera : obj.camera
155                    obj.bluetooth = obj.bluetooth == 0 ? array[index].bluetooth : obj.bluetooth
156                    obj.flashlight = obj.flashlight == 0 ? array[index].flashlight : obj.flashlight
157                    obj.audio = obj.audio ? array[index].audio : obj.audio
158                    obj.wifiscan = obj.wifiscan == 0 ? array[index].wifiscan : obj.wifiscan
159                } else {
160                    res.push(array[index])
161                }
162            }
163        }
164        res.forEach(item => {
165            EnergyPowerStruct.setPowerFrame(item, 5, startNS || 0, endNS || 0,
166                totalNS || 0, frame)
167            let max = (item.cpu || 0) + (item.location || 0) + (item.gpu || 0) + (item.display || 0) + (item.camera
168                || 0) + (item.bluetooth || 0) + (item.flashlight || 0) + (item.audio || 0) + (item.wifiscan || 0)
169            if (max > EnergyPowerStruct.maxPower) {
170                EnergyPowerStruct.maxPower = max
171            }
172        })
173    }
174}
175
176export class EnergyPowerStruct extends BaseStruct {
177    static maxPower: number = 0
178    static maxPowerName: string = "0"
179    static powerItemNumber: number = 9
180    static currentTextWidth: number = 0
181    static rowHeight: number = 200
182    static appName: string | undefined
183    static hoverEnergyPowerStruct: EnergyPowerStruct | undefined;
184    static selectEnergyPowerStruct: EnergyPowerStruct | undefined;
185    name: string | undefined
186    ts: number = 0
187    cpu: number = 0
188    location: number = 0
189    gpu: number = 0
190    display: number = 0
191    camera: number = 0
192    bluetooth: number = 0
193    flashlight: number = 0
194    audio: number = 0
195    wifiscan: number = 0
196
197    static draw(req: RequestMessage, index: number, data: EnergyPowerStruct) {
198        if (data.frame) {
199            let width = data.frame.width || 0;
200            req!.context.globalAlpha = 1.0;
201            req!.context.lineWidth = 1;
202            this.currentTextWidth = 0
203            let cpuHeight = this.drawHistogram(req, data, -1, data.cpu!, "CPU");
204            let locationHeight = this.drawHistogram(req, data, cpuHeight, data.location!, "LOCATION");
205            let gpuHeight = this.drawHistogram(req, data, cpuHeight - locationHeight, data.gpu!,
206                "GPU");
207            let displayHeight = this.drawHistogram(req, data,
208                cpuHeight - locationHeight - gpuHeight, data.display!, "DISPLAY");
209            let cameraHeight = this.drawHistogram(req, data, cpuHeight - locationHeight - gpuHeight -
210                displayHeight, data.camera!, "CAMERA");
211            let bluetoothHeight = this.drawHistogram(req, data, cpuHeight - locationHeight - gpuHeight -
212                displayHeight - cameraHeight, data.bluetooth!, "BLUETOOTH");
213            let flashlightHeight = this.drawHistogram(req, data, cpuHeight - locationHeight - gpuHeight -
214                displayHeight - cameraHeight - bluetoothHeight, data.flashlight!, "FLASHLIGHT");
215            let audioHeight = this.drawHistogram(req, data, cpuHeight - locationHeight - gpuHeight -
216                displayHeight - cameraHeight - bluetoothHeight - flashlightHeight, data.audio!,
217                "AUDIO");
218            let wifiHeight = this.drawHistogram(req, data, cpuHeight - locationHeight - gpuHeight -
219                displayHeight - cameraHeight - bluetoothHeight - flashlightHeight - audioHeight, data.wifiscan!,
220                "WIFISCAN");
221            let maxPointY = this.drawPolyline(req, index, data)
222            if (data.ts === EnergyPowerStruct.hoverEnergyPowerStruct?.ts) {
223                req.context.globalAlpha = 1
224                req!.context.lineWidth = 2;
225                req.context.fillStyle = "#333"
226                req!.context.strokeRect(data.frame!.x, maxPointY, data.frame!.width, req.canvas.width - maxPointY);
227            }
228        }
229        req!.context.globalAlpha = 1.0;
230        req!.context.lineWidth = 1;
231    }
232
233    static drawHistogram(req: RequestMessage, data: EnergyPowerStruct, height: number, itemValue: number,
234                         textItem: string): number {
235        let histogramColor = this.getHistogramColor(textItem);
236        req!.context.fillStyle = histogramColor;
237        req!.context.strokeStyle = histogramColor;
238        let dataHeight: number = Math.floor(((itemValue || 0) * (this.rowHeight - 40)) /
239            EnergyPowerStruct.maxPower);
240        let drawStartY = 0;
241
242        if (height == -1) {
243            drawStartY = data.frame!.y + this.rowHeight - dataHeight + 4;
244            req!.context.fillRect(data.frame!.x, drawStartY, data.frame!.width, dataHeight);
245            return drawStartY;
246        } else {
247            drawStartY = height - dataHeight;
248            req!.context.fillRect(data.frame!.x, drawStartY, data.frame!.width, dataHeight);
249            return dataHeight;
250        }
251    }
252
253    static drawPolyline(req: RequestMessage, index: number, data: EnergyPowerStruct) {
254        let pointX = ns2x(((data.ts || 0) + 500000000), req.startNS, req.endNS, req.totalNS, req.frame);
255        let maxHeight = (data.cpu || 0) + (data.location || 0) + (data.gpu || 0) + (data.display || 0) + (data.camera
256            || 0) + (data.bluetooth || 0) + (data.flashlight || 0) + (data.audio || 0) + (data.wifiscan || 0)
257        let drawHeight: number = Math.floor(((maxHeight || 0) * (this.rowHeight - 40)) /
258            EnergyPowerStruct.maxPower);
259        let drawY = data.frame!.y + this.rowHeight - drawHeight + 5
260        req!.context.fillStyle = "#ED6F21";
261        req!.context.strokeStyle = "#ED6F21";
262
263        if (index == 0) {
264            req.context.beginPath()
265            req.context.arc(pointX, drawY, 4, 0, 2 * Math.PI)
266            req.context.fill()
267            req.context.moveTo(pointX, drawY)
268        } else {
269            req.context.lineTo(pointX, drawY);
270            req.context.stroke();
271            req.context.beginPath()
272            req.context.arc(pointX, drawY, 4, 0, 2 * Math.PI)
273            req.context.fill()
274        }
275        return drawY
276    }
277
278    static setPowerFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
279        let startPointX: number
280        let endPointX: number
281        if ((node.ts || 0) < startNS) {
282            startPointX = 0
283        } else {
284            startPointX = ns2x((node.ts || 0), startNS, endNS, totalNS, frame);
285        }
286        if ((node.ts + 1000000000) > endNS) {
287            endPointX = frame.width;
288        } else {
289            endPointX = ns2x((node.ts + 1000000000), startNS, endNS, totalNS, frame);
290        }
291        let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
292        if (!node.frame) {
293            node.frame = {};
294        }
295        node.frame.x = Math.floor(startPointX);
296        node.frame.y = frame.y + padding;
297        node.frame.width = Math.ceil(frameWidth);
298        node.frame.height = Math.floor(frame.height - padding * 2);
299    }
300
301    static getHistogramColor(textItem: string): string {
302        switch (textItem) {
303            case 'CPU':
304                return "#92D6CC";
305            case 'LOCATION':
306                return "#61CFBE"
307            case 'GPU':
308                return "#86C5E3"
309            case 'DISPLAY':
310                return "#46B1E3"
311            case 'CAMERA':
312                return "#C386F0"
313            case 'BLUETOOTH':
314                return "#8981F7"
315            case 'AUDIO':
316                return "#AC49F5"
317            case 'WIFISCAN':
318                return "#92C4BD"
319            default:
320                return "#564AF7"
321        }
322    }
323}
324