• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// @ts-nocheck
2/*
3 * Copyright (C) 2022 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {BaseElement, element} from "../../../../base-ui/BaseElement.js";
18import {CpuStruct} from "../../../bean/CpuStruct.js";
19import {LitTable} from "../../../../base-ui/table/lit-table.js";
20import "../../../../base-ui/table/lit-table-column.js";
21
22import {
23    queryBinderArgsByArgset,
24    queryWakeUpThread_WakeThread,
25    queryWakeUpThread_WakeTime
26} from "../../../database/SqlLite.js";
27import {WakeupBean} from "../../../bean/WakeupBean.js";
28import {ThreadStruct} from "../../../bean/ThreadStruct.js";
29import {ProcessMemStruct} from "../../../bean/ProcessMemStruct.js";
30import {FuncStruct} from "../../../bean/FuncStruct.js";
31import {SpApplication} from "../../../SpApplication.js";
32
33const STATUS_MAP: any = {
34    D: "Uninterruptible Sleep",
35    S: "Sleeping",
36    R: "Runnable",
37    "Running": "Running",
38    "R+": "Runnable (Preempted)",
39    DK: "Uninterruptible Sleep + Wake Kill",
40    I: "Task Dead",
41    T: "Stopped",
42    t: "Traced",
43    X: "Exit (Dead)",
44    Z: "Exit (Zombie)",
45    K: "Wake Kill",
46    W: "Waking",
47    P: "Parked",
48    N: "No Load"
49}
50const INPUT_WORD = "This is the interval from when the task became eligible to run \n(e.g.because of notifying a wait queue it was a suspended on) to\n when it started running."
51
52export function getTimeString(ns: number): string {
53    let currentNs = ns
54    let hour1 = 3600_000_000_000
55    let minute1 = 60_000_000_000
56    let second1 = 1_000_000_000; // 1 second
57    let millisecond1 = 1_000_000; // 1 millisecond
58    let microsecond1 = 1_000; // 1 microsecond
59    let res = "";
60    if (currentNs >= hour1) {
61        res += Math.floor(currentNs / hour1) + "h ";
62        currentNs = currentNs - Math.floor(currentNs / hour1) * hour1
63    }
64    if (currentNs >= minute1) {
65        res += Math.floor(currentNs / minute1) + "m ";
66        currentNs = currentNs - Math.floor(ns / minute1) * minute1
67    }
68    if (currentNs >= second1) {
69        res += Math.floor(currentNs / second1) + "s ";
70        currentNs = currentNs - Math.floor(currentNs / second1) * second1
71    }
72    if (currentNs >= millisecond1) {
73        res += Math.floor(currentNs / millisecond1) + "ms ";
74        currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1
75    }
76    if (currentNs >= microsecond1) {
77        res += Math.floor(currentNs / microsecond1) + "μs ";
78        currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1
79    }
80    if (currentNs > 0) {
81        res += currentNs + "ns ";
82    }
83    return res
84}
85
86@element('tabpane-current-selection')
87export class TabPaneCurrentSelection extends BaseElement {
88    weakUpBean: WakeupBean | null | undefined;
89    private tbl: LitTable | null | undefined;
90    private tableObserver: MutationObserver | undefined
91    // @ts-ignore
92    private dpr: any = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
93
94    set data(value: any) {
95        this.setCpuData(value)
96    }
97
98    setCpuData(data: CpuStruct, callback: ((data: WakeupBean | null) => void) | undefined = undefined) {
99        let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle");
100        if (leftTitle) {
101            leftTitle.innerText = "Slice Details"
102        }
103        let list: any[] = []
104        let process = data.processName
105        let processId = data.processId
106        if (process == null || process == "") {
107            process = data.name
108            processId = data.tid
109        }
110        let state = ""
111        if (data.end_state) {
112            state = STATUS_MAP[data.end_state]
113        } else if (data.end_state == "" || data.end_state == null) {
114            state = ""
115        } else {
116            state = "Unknown State"
117        }
118        list.push({name: 'Process', value: `${process || 'Process'} [${processId}]`})
119        list.push({name: 'Thread', value: `${data.name || 'Process'} [${data.tid}]`})
120        list.push({name: 'CmdLine', value: data.processCmdLine})
121        list.push({name: 'StartTime', value: getTimeString(data.startTime || 0)})
122        list.push({name: 'Duration', value: getTimeString(data.dur || 0)})
123        list.push({name: 'Prio', value: data.priority || 0})
124        list.push({name: 'End State', value: state})
125        this.queryWakeUpData(data).then((bean) => {
126            if (callback) {
127                callback(bean)
128            }
129            this.tbl!.dataSource = list
130            let rightArea: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#right-table");
131            let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle");
132            let canvas = this.initCanvas();
133            if (bean != null) {
134                this.weakUpBean = bean;
135                if (rightArea != null && rightArea) {
136                    rightArea.style.visibility = "visible"
137                }
138                if (rightTitle != null && rightTitle) {
139                    rightTitle.style.visibility = "visible"
140                }
141                this.drawRight(canvas, bean)
142            } else {
143                this.weakUpBean = null;
144                if (rightArea != null && rightArea) {
145                    rightArea.style.visibility = "hidden"
146                }
147                if (rightTitle != null && rightTitle) {
148                    rightTitle.style.visibility = "hidden"
149                }
150            }
151        })
152    }
153
154    setFunctionData(data: FuncStruct) {//方法信息
155        this.initCanvas()
156        let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle");
157        let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle");
158        if (rightTitle) {
159            rightTitle.style.visibility = "hidden"
160        }
161        if (leftTitle) {
162            leftTitle.innerText = "Slice Details"
163        }
164        let list: any[] = []
165        list.push({name: 'Name', value: data.funName})
166        list.push({name: 'StartTime', value: getTimeString(data.startTs || 0)})
167        list.push({name: 'Duration', value: getTimeString(data.dur || 0)})
168        if (FuncStruct.isBinder(data)) {
169            if (data.argsetid != undefined) {
170                queryBinderArgsByArgset(data.argsetid).then((argset) => {
171                    argset.forEach((item) => {
172                        list.push({name: item.keyName, value: item.strValue})
173                    })
174
175                });
176            }
177            list.push({name: 'depth', value: data.depth})
178            list.push({name: 'arg_set_id', value: data.argsetid})
179        }
180        this.tbl!.dataSource = list
181
182    }
183
184    setMemData(data: ProcessMemStruct) {
185        this.initCanvas()
186        let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle");
187        if (leftTitle) {
188            leftTitle.innerText = "Counter Details"
189        }
190        let list: any[] = []
191        list.push({name: 'Start time', value: getTimeString(data.startTime || 0)})
192        list.push({name: 'Value', value: data.value})
193        list.push({name: 'Delta', value: data.delta})
194        list.push({name: 'Duration', value: getTimeString(data.duration || 0)})
195        this.tbl!.dataSource = list
196
197    }
198
199    setThreadData(data: ThreadStruct) {
200        this.initCanvas()
201        let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle");
202        let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle");
203        if (rightTitle) {
204            rightTitle.style.visibility = "hidden"
205        }
206        if (leftTitle) {
207            leftTitle.innerText = "Counter Details"
208        }
209        let list: any[] = []
210        list.push({name: 'StartTime', value: getTimeString(data.startTime || 0)})
211        list.push({name: 'Duration', value: getTimeString(data.dur || 0)})
212        let state = ""
213        if (data.state) {
214            state = STATUS_MAP[data.state]
215        } else if (data.state == "" || data.state == null) {
216            state = ""
217        } else {
218            state = "Unknown State"
219        }
220        if ("Running" == state) {
221            state = state + " on CPU " + data.cpu;
222        }
223        list.push({name: 'State', value: state})
224        let processName = data.processName;
225        if (processName == null || processName == "" || processName.toLowerCase() == "null") {
226            processName = data.name;
227        }
228        list.push({name: 'Process', value: processName + " [" + data.pid + "] "})
229        this.tbl!.dataSource = list
230    }
231
232
233    async queryWakeUpData(data: CpuStruct) {
234        let wb: WakeupBean | null = null
235        if (data.id == undefined || data.startTime == undefined) {
236            return null
237        }
238        let wakeupTimes = await queryWakeUpThread_WakeTime(data.id, data.startTime)// 3,4835380000
239        if (wakeupTimes != undefined && wakeupTimes.length > 0) {
240            let wakeupTime = wakeupTimes[0]
241            if (wakeupTime.wakeTs != undefined && wakeupTime.preRow != undefined && wakeupTime.wakeTs < wakeupTime.preRow) {
242                return null
243            }
244            if (wakeupTime.wakeTs == undefined) {
245                return null
246            }
247            let wakeupBeans = await queryWakeUpThread_WakeThread(wakeupTime.wakeTs)
248            if (wakeupBeans != undefined && wakeupBeans.length > 0) {
249                wb = wakeupBeans[0]
250                if (wb != null) {
251                    if (wakeupTime.wakeTs != undefined && wakeupTime.startTs != undefined) {
252                        wb.wakeupTime = wakeupTime.wakeTs - wakeupTime.startTs
253                    }
254                    wb.schedulingLatency = data.startTime || 0 - (wb.wakeupTime || 0)
255                    if (wb.process == null) {
256                        wb.process = wb.thread;
257                    }
258                    if (wb.pid == undefined) {
259                        wb.pid = wb.tid;
260                    }
261                    wb.schedulingDesc = INPUT_WORD
262                }
263            }
264        }
265        return wb
266    }
267
268    initCanvas(): HTMLCanvasElement | null {
269        let canvas = this.shadowRoot!.querySelector("#rightDraw")
270        let width = getComputedStyle(this.tbl!).getPropertyValue("width")
271        let height = getComputedStyle(this.tbl!).getPropertyValue("height")
272        if (canvas != null) {
273            canvas.width = Math.round(Number(width.replace("px", "")) * this.dpr)
274            canvas.height = Math.round(Number(height.replace("px", "")) * this.dpr)
275            canvas.style.width = width
276            canvas.style.height = height
277        }
278        SpApplication.skinChange = (val: boolean) => {
279            this.drawRight(canvas, this.weakUpBean)
280        }
281        return canvas
282    }
283
284    drawRight(cavs: HTMLCanvasElement | null, wakeupBean: WakeupBean | null) {
285        if (cavs == null) {
286            return
287        }
288        let context = cavs.getContext("2d");
289        if (context != null) {
290            if (document.querySelector<SpApplication>("sp-application").dark) {
291                context.strokeStyle = "#ffffff";
292                context.fillStyle = "#ffffff";
293            } else {
294                context.strokeStyle = "#000000";
295                context.fillStyle = "#000000";
296            }
297            context.lineWidth = this.dprToPx(2);
298            context.moveTo(this.dprToPx(10), this.dprToPx(15))
299            context.lineTo(this.dprToPx(10), this.dprToPx(125))
300            context.stroke();
301            //绘制菱形
302            context.lineWidth = this.dprToPx(1);
303            context.beginPath()
304            context.moveTo(this.dprToPx(10), this.dprToPx(30))
305            context.lineTo(this.dprToPx(4), this.dprToPx(40))
306            context.lineTo(this.dprToPx(10), this.dprToPx(50))
307            context.lineTo(this.dprToPx(16), this.dprToPx(40))
308            context.lineTo(this.dprToPx(10), this.dprToPx(30))
309            context.closePath()
310            context.fill()
311            context.font = this.dprToPx(12) + "px sans-serif";
312            let strList = []
313            strList.push("wakeup @ " + getTimeString(wakeupBean?.wakeupTime || 0) + " on CPU " + wakeupBean?.cpu + " by")
314            strList.push("P:" + wakeupBean?.process + " [ " + wakeupBean?.pid + " ]")
315            strList.push("F:" + wakeupBean?.thread + " [ " + wakeupBean?.tid + " ]")
316            strList.forEach((str, index) => {
317                if (context != null) {
318                    context.fillText(str
319                        , this.dprToPx(40), this.dprToPx(40 + 16 * index))
320                }
321            })
322            context.lineWidth = this.dprToPx(2);
323            context.lineJoin = "bevel"
324            context.moveTo(this.dprToPx(10), this.dprToPx(95))
325            context.lineTo(this.dprToPx(20), this.dprToPx(90))
326            context.moveTo(this.dprToPx(10), this.dprToPx(95))
327            context.lineTo(this.dprToPx(20), this.dprToPx(100))
328            context.moveTo(this.dprToPx(10), this.dprToPx(95))
329            context.lineTo(this.dprToPx(80), this.dprToPx(95))
330            context.lineTo(this.dprToPx(70), this.dprToPx(90))
331            context.moveTo(this.dprToPx(80), this.dprToPx(95))
332            context.lineTo(this.dprToPx(70), this.dprToPx(100))
333            context.stroke();
334            context.font = this.dprToPx(12) + "px sans-serif";
335            context.fillText("Scheduling latency:" + getTimeString(wakeupBean?.schedulingLatency || 0)
336                , this.dprToPx(90), this.dprToPx(100))
337            context.font = this.dprToPx(10) + "px sans-serif";
338            INPUT_WORD.split("\n").forEach((str, index) => {
339                context?.fillText(str
340                    , this.dprToPx(90), this.dprToPx(120 + 12 * index))
341            })
342
343        }
344    }
345
346    dprToPx(num: number) {
347        return Math.round(num * this.dpr)
348    }
349
350    initElements(): void {
351        this.tbl = this.shadowRoot?.querySelector<LitTable>('#selectionTbl');
352        this.tbl.addEventListener("column-click", ev => {
353            console.log(ev.detail);
354        })
355        this.addTableObserver()
356    }
357
358    addTableObserver() {
359        let MutationObserver = window.MutationObserver
360        this.tableObserver = new MutationObserver((list) => {
361            console.log(this.tbl);
362            if (this.tbl) {
363                let width = getComputedStyle(this.tbl).getPropertyValue("width")
364                let height = getComputedStyle(this.tbl).getPropertyValue("height")
365                console.log(width);
366                console.log(height);
367            }
368        })
369        let selector = this.shadowRoot?.querySelector(".left-table");
370        this.tableObserver?.observe(selector!, {attributes: true, attributeFilter: ['style'], attributeOldValue: true})
371    }
372
373    initHtml(): string {
374        return `
375        <style>
376            .current-title{
377                width: 100%;
378                display: flex;
379                top: 0;
380                background: var(--dark-background,#ffffff);
381                position: sticky;
382            }
383            .current-title h2{
384                width: 50%;
385                padding: 0 10px;
386                font-size: 16px;
387                font-weight: 400;
388                visibility: visible;
389            }
390            .bottom-scroll-area{
391                display: flex;
392                height: auto;
393                overflow-y: auto;
394            }
395            .left-table{
396                width: 50%;
397                padding: 0 10px;
398            }
399            .right-table{
400                width: 50%;
401            }
402        </style>
403        <div style="width: 100%;height: auto;position: relative">
404            <div class="current-title">
405                <h2 id="leftTitle"></h2>
406                <h2 id="rightTitle">Scheduling Latency</h2>
407            </div>
408            <div class="bottom-scroll-area">
409                <div class="left-table">
410                    <lit-table id="selectionTbl" no-head style="height: auto">
411                        <lit-table-column title="name" data-index="name" key="name" align="flex-start"  width="180px">
412                            <template><div>{{name}}</div></template>
413                        </lit-table-column>
414                        <lit-table-column title="value" data-index="value" key="value" align="flex-start" ></lit-table-column>
415                    </lit-table>
416                </div>
417                <div class="right-table">
418                    <canvas id="rightDraw" style="width: 100%;height: 100%;"></canvas>
419                </div>
420            </div>
421        </div>
422        `;
423    }
424
425}
426