• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2023 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 { BaseElement, element } from '../../../../../base-ui/BaseElement';
17import '../../../../../base-ui/radiobox/LitRadioBox';
18import { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
19import '../../../../../base-ui/popover/LitPopoverV';
20import { LitPopover } from '../../../../../base-ui/popover/LitPopoverV';
21import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection';
22import { queryCoreRunningThread } from '../../../../database/sql/ProcessThread.sql';
23import { MtSettingHtml } from '../TabPaneMt.html';
24import { LitCheckBox } from '../../../../../base-ui/checkbox/LitCheckBox';
25import '../../../../../base-ui/checkbox/LitCheckBox';
26import { MeterHeaderClick, HanldParalLogic } from './ParallelUtil';
27import { TabPaneFilter } from '../TabPaneFilter';
28import { Utils } from '../../base/Utils';
29
30const UNIT: number = 1000000.0;
31const NUM_DIGITS: number = 3;
32const CORE_NUM: number = 12;
33const SMALL_CPU_NUM: Array<number> = [0, 1, 2, 3];
34const MID_CPU_NUM12: Array<number> = [4, 5, 6, 7, 8, 9];
35const LARGE_CPU_NUM12: Array<number> = [10, 11];
36const CORE_JSON = {
37    'group1': [4, 5],
38    'group2': [6, 7],
39    'group3': [8, 9],
40    'group4': [10, 11],
41};
42export class CpuStatus {
43    cpu: number = 0;
44    small: boolean = false;
45    medium: boolean = false;
46    large: boolean = false;
47}
48@element('tabpane-mt-parallel')
49export class TabPaneMtParallel extends BaseElement {
50    private parallelTable: LitTable | null | undefined;
51    private litSettingPopoverEl: LitPopover | null | undefined;
52    private litGourpPopoverEl: LitPopover | null | undefined;
53    private cpuTbl: HTMLDivElement | null | undefined;
54    private groupContentDiv: HTMLDivElement | null | undefined;
55    private selectionParam: SelectionParam | undefined;
56    private dataSourceMap: Map<string, unknown> = new Map<string, unknown>();
57    private leftStartNs: number = 0;
58    private rightEndNs: number = 0;
59    private midCores: Array<number> = [];
60    private largeCores: Array<number> = [];
61    private smallCores: Array<number> = [];
62    private isCreateCpu: boolean = true;
63    private isCreateGroup: boolean = true;
64    private coreTypeMap: Map<string, unknown> = new Map<string, unknown>();
65    private bottomFilterEl: TabPaneFilter | null | undefined;
66    private addGroupArr: Array<number> = [];
67    // @ts-ignore
68    private bufferGroupMap: Map<string, Array<unknown>> = new Map<string, unknown>();
69    private isReset: boolean = true;
70
71    set data(threadStatesParam: SelectionParam) {
72        if (this.selectionParam === threadStatesParam) { return; };
73        this.selectionParam = threadStatesParam;
74        this.leftStartNs = this.selectionParam!.leftNs + this.selectionParam!.recordStartNs;
75        this.rightEndNs = this.selectionParam!.rightNs + this.selectionParam!.recordStartNs;
76        this.isCreateCpu = true;
77        this.parallelTable!.recycleDataSource = [];
78        this.initDefaultConfig();
79        this.resetSomeConfig(false);
80    }
81    initElements(): void {
82        this.parallelTable = this.shadowRoot!.querySelector<LitTable>('#tb-parallel');
83        this.bottomFilterEl = this.shadowRoot?.querySelector('#filter');
84        this.litSettingPopoverEl = this.bottomFilterEl?.shadowRoot?.querySelector('#data-core-popover');
85        this.litGourpPopoverEl = this.bottomFilterEl?.shadowRoot?.querySelector('#group-mining-popover');
86        this.cpuTbl = this.litGourpPopoverEl!.querySelector<HTMLDivElement>('#tb_cpu');
87        this.groupContentDiv = this.litGourpPopoverEl!.querySelector<HTMLDivElement>('.add_content');
88        this.cpuSettingElListener();
89        this.groupSettingElListener();
90    }
91    //Cpu Setting 气泡相关按钮监听
92    cpuSettingElListener(): void {
93        this.litSettingPopoverEl!.querySelector<HTMLDivElement>('#core-mining')!.onclick = (e): void => {
94            if (this.isCreateCpu) {
95                this.initDefaultConfig();
96                this.isCreateCpu = false;
97                this.bottomFilterEl!.setCoreConfigList(Utils.getInstance().getWinCpuCount(), this.smallCores, this.midCores, this.largeCores);
98            };
99        };
100        this.litSettingPopoverEl!.querySelector<HTMLDivElement>('.confirm-button')!.addEventListener('click', (e: unknown) => {
101            this.resetSomeConfig(true);
102        });
103        this.litSettingPopoverEl!.querySelector<HTMLDivElement>('.reset-button')!.addEventListener('click', (e: unknown) => {
104            this.isCreateCpu = true;
105            this.initDefaultConfig();
106            this.resetSomeConfig(false);
107        });
108    }
109    //Group Setting 气泡相关按钮监听
110    groupSettingElListener(): void {
111        this.litGourpPopoverEl!.querySelector<HTMLDivElement>('#group-mining')!.addEventListener('click', (e: unknown) => {
112            this.addGroupArr = [];
113            if (this.isCreateGroup) {
114                this.groupContentDiv!.innerHTML = '';
115                this.getGroupTableLine();
116                //如果核数为12,默认配置分组
117                if (Utils.getInstance().getWinCpuCount() === CORE_NUM && this.isReset) {
118                    this.isReset = false;
119                    const myMap = new Map(Object.entries(CORE_JSON));
120                    for (const val of myMap.values()) {
121                        this.initGroupFn(val);
122                    }
123                }
124            } else {
125                this.getGroupTableLine();
126            }
127        });
128        this.litGourpPopoverEl!.querySelector<HTMLDivElement>('.add_group_button')!.addEventListener('click', (e: unknown) => {
129            this.initGroupFn(this.addGroupArr);
130            //每次需要添加的数组,在每次添加完后清空
131            this.addGroupArr = [];
132        });
133        this.litGourpPopoverEl!.querySelector<HTMLDivElement>('.cut_group_button')!.addEventListener('click', (e: unknown) => {
134            //支持撤回已配置好的分组
135            if (!this.groupContentDiv!.childNodes.length) { return };
136            let parts: unknown = this.groupContentDiv!.lastChild!.textContent?.split(':');
137            // @ts-ignore
138            if (this.bufferGroupMap.has(parts[0])) { this.bufferGroupMap.delete(parts[0]) };
139            this.groupContentDiv!.removeChild(this.groupContentDiv!.lastChild!);
140            this.addGroupArr = [];
141            this.getGroupTableLine('cut');
142        });
143        this.litGourpPopoverEl!.querySelector<HTMLDivElement>('.confirm-group-button')!.addEventListener('click', (e: unknown) => {
144            this.updateDataSource(true);
145            // @ts-ignore
146            this.litGourpPopoverEl!.visible = false;
147        });
148        this.litGourpPopoverEl!.querySelector<HTMLDivElement>('.reset-group-button')!.addEventListener('click', (e: unknown) => {
149            this.resetGroup(false);
150            this.isCreateCpu = true;
151            this.initDefaultConfig();
152            this.updateDataSource(false);
153            // @ts-ignore
154            this.litGourpPopoverEl!.visible = false;
155        });
156    }
157    //group setting 重置
158    resetGroup(isRest: boolean): void {
159        this.isCreateGroup = true;
160        this.bufferGroupMap.clear();
161        this.isReset = !isRest;
162    }
163    //当cpu setting点击重置或者确认时,需要重置Group setting的数据
164    resetSomeConfig(isRest: boolean): void {
165        this.resetGroup(isRest);
166        this.updateDataSource(isRest);
167        // @ts-ignore
168        this.litSettingPopoverEl!.visible = false;
169    }
170    //更新treeData
171    updateDataSource(flag: boolean): void {
172        let param = flag ? this.bufferGroupMap.size !== 0 : Utils.getInstance().getWinCpuCount() === CORE_NUM;
173        let value = flag ? this.bufferGroupMap : new Map(Object.entries(CORE_JSON));
174        if ((this.midCores.length || this.largeCores.length || this.smallCores.length) && param) {
175            this.coreTypeMap.clear();
176            this.dataSourceMap.clear();
177            this.parallelTable!.loading = true;
178            this.getMtParallelData(value).then(() => {
179                this.parallelTable!.recycleDataSource = [...this.dataSourceMap.values()];
180                this.parallelTable!.loading = false;
181                MeterHeaderClick(this.parallelTable, [...this.dataSourceMap.values()]);
182            });
183        } else {
184            this.parallelTable!.recycleDataSource = [];
185            MeterHeaderClick(this.parallelTable, []);
186        }
187    }
188    async getMtParallelData(obj: Map<string, unknown>) :Promise<void> {
189        let cpuObj: unknown = { 'L': this.largeCores, 'M': this.midCores, 'S': this.smallCores };
190        let processIds: Array<number> = [...new Set(this.selectionParam!.processIds)];
191        for (const [key, cpuGroup] of obj.entries()) {
192            //判断配的的组是否在同一个核分类中,如果在,返回是那个核分类,反之,返回null
193            // @ts-ignore
194            let core = this.handleSamePhysicsCore(cpuGroup, cpuObj);
195            if (core === null) { continue };
196            // @ts-ignore
197            let res: unknown = await queryCoreRunningThread(processIds, this.selectionParam!.threadIds, cpuGroup, this.leftStartNs, this.rightEndNs);
198            // @ts-ignore
199            this.handleTreeProcessData(res, core, key, cpuGroup);
200        }
201        //计算根节点数据并处理第二层数据的单位及保留位数
202        for (const [i, item] of this.coreTypeMap) {
203            // @ts-ignore
204            if (this.dataSourceMap.has(`${item.pid}`)) {
205                // @ts-ignore
206                let obj = this.dataSourceMap.get(`${item.pid}`);
207                // @ts-ignore
208                item.allParallel = ((item.parallelDur * item.parallelNum / item.dur) * 100).toFixed(NUM_DIGITS);
209                // @ts-ignore
210                obj.dur += item.dur;
211                // @ts-ignore
212                obj.parallelDur += item.parallelDur;
213                // @ts-ignore
214                obj.load += item.load;
215                // @ts-ignore
216                obj.parallelNum = item.parallelNum;
217                // @ts-ignore
218                item.dur = (item.dur / UNIT).toFixed(NUM_DIGITS);
219                // @ts-ignore
220                item.parallelDur = (item.parallelDur / UNIT).toFixed(NUM_DIGITS);
221                // @ts-ignore
222                item.load = item.load.toFixed(NUM_DIGITS);
223                // @ts-ignore
224                obj.children.push(item);
225            }
226        }
227        //处理根节点数据的单位及保留位数
228        for (const [i, item] of this.dataSourceMap) {
229            // @ts-ignore
230            item.allParallel = ((item.parallelDur * item.parallelNum / item.dur) * 100).toFixed(NUM_DIGITS);
231            // @ts-ignore
232            item.dur = (item.dur / UNIT).toFixed(NUM_DIGITS);
233            // @ts-ignore
234            item.parallelDur = (item.parallelDur / UNIT).toFixed(NUM_DIGITS);
235            // @ts-ignore
236            item.load = item.load.toFixed(NUM_DIGITS);
237        }
238    }
239
240    //判断自配的相同物理核是否符合计算MT并行度的要求
241    handleSamePhysicsCore(arr: unknown, obj: { 'L': Array<number>; 'M': Array<number>; 'S': Array<number> }): string | null {
242        let core = null;
243        // @ts-ignore
244        if (arr.length > 2) { return null }
245        for (const [key, val] of Object.entries(obj)) {
246            // @ts-ignore
247            let isSet = val.includes(arr[0]) && val.includes(arr[1]);
248            if (isSet) {
249                core = key;
250            }
251        }
252        return core;
253    }
254
255    handleTreeProcessData(result: unknown, key: string, gourpKey: string, gourp: Array<number>): void {
256        let coreMap: Map<string, unknown> = new Map<string, unknown>();
257        // @ts-ignore
258        for (let i = 0; i < result.length; i++) {
259            // @ts-ignore
260            let stateItem = result[i];
261            //处理框选区域前后的边界ts
262            if (stateItem.ts < this.leftStartNs) {
263                stateItem.ts = this.leftStartNs;
264            }
265            if (stateItem.endTs > this.rightEndNs) {
266                stateItem.endTs = this.rightEndNs;
267            }
268            let dur = stateItem.endTs - stateItem.ts;
269            //以pid为key值添加MTTable数据源的最外层数据结构
270            if (!this.dataSourceMap.has(`${stateItem.pid}`)) {
271                this.dataSourceMap.set(`${stateItem.pid}`, {
272                    pid: stateItem.pid,
273                    tid: stateItem.tid,
274                    title: stateItem.pName ? `${stateItem.pName} ${stateItem.pid}` : `[NULL] ${stateItem.pid}`,
275                    group: '',
276                    dur: null,
277                    parallelNum: null,
278                    parallelDur: null,
279                    allParallel: null,
280                    load: null,
281                    tCount: null,
282                    children: []
283                });
284            };
285            if (coreMap.has(`${stateItem.pid}`)) {
286                let obj = coreMap.get(`${stateItem.pid}`);
287                // @ts-ignore
288                let setArr = new Set(obj.tidArr);
289                if (!(setArr.has(stateItem.tid))) {
290                    setArr.add(stateItem.tid);
291                    // @ts-ignore
292                    obj.tidArr.push(stateItem.tid);
293                }
294                // @ts-ignore
295                obj.gourpDur += dur;
296                // @ts-ignore
297                obj.stateItem.push(stateItem);
298            } else {
299                coreMap.set(`${stateItem.pid}`, {
300                    pid: stateItem.pid,
301                    tid: stateItem.tid,
302                    gourpDur: dur,
303                    tidArr: [stateItem.tid],
304                    stateItem: [stateItem],
305                });
306            };
307        };
308        this.mergeTreeCoreData(coreMap, key, gourpKey, gourp);
309    }
310    //处理树结构最终需要的信息数据
311    // @ts-ignore
312    mergeTreeCoreData(map: Map<string, unknown>, coreKey: string, gourpKey: string, gourp: Array<number>): void {
313        let str = gourp.join(',');
314        for (const [key, value] of map) {
315            let pDur: number = 0;
316            // @ts-ignore
317            pDur = HanldParalLogic(this.hanldMapLogic, value, pDur);
318            // @ts-ignore
319            let paral = (pDur * gourp.length / value.gourpDur) * 100;
320            // @ts-ignore
321            let load = value.gourpDur / ((100 * UNIT) * Utils.getInstance().getWinCpuCount());
322            let groupObj = {
323                // @ts-ignore
324                pid: value.pid,
325                // @ts-ignore
326                tid: value.tid,
327                title: '',
328                group: `${gourpKey}:${str}`,
329                // @ts-ignore
330                dur: (value.gourpDur / UNIT).toFixed(NUM_DIGITS),
331                parallelNum: gourp.length,
332                parallelDur: (pDur / UNIT).toFixed(NUM_DIGITS),
333                allParallel: paral.toFixed(NUM_DIGITS),
334                load: load.toFixed(NUM_DIGITS),
335                // @ts-ignore
336                tCount: value.tidArr.length,
337                children: []
338            };
339            // @ts-ignore
340            if (this.coreTypeMap.has(`${value.pid} ${coreKey}`)) {
341                // @ts-ignore
342                let obj = this.coreTypeMap.get(`${value.pid} ${coreKey}`);
343                // @ts-ignore
344                obj.dur += value.gourpDur;
345                // @ts-ignore
346                obj.parallelDur += pDur;
347                // @ts-ignore
348                obj.load += load;
349                // @ts-ignore
350                obj.children.push(groupObj);
351            } else {
352                // @ts-ignore
353                this.coreTypeMap.set(`${value.pid} ${coreKey}`, {
354                    // @ts-ignore
355                    pid: value.pid,
356                    // @ts-ignore
357                    tid: value.tid,
358                    title: `${coreKey}`,
359                    group: '',
360                    // @ts-ignore
361                    dur: value.gourpDur,
362                    parallelNum: gourp.length,
363                    parallelDur: pDur,
364                    allParallel: null,
365                    load: load,
366                    tCount: null,
367                    children: [groupObj]
368                });
369            }
370        }
371    }
372
373    //每次stateItem计算的的结果
374    hanldMapLogic(dumpObj: unknown, value?: unknown, param?: unknown): void {
375        // @ts-ignore
376        if (dumpObj.len !== 1) {
377            // @ts-ignore
378            param += dumpObj.endTs - dumpObj.ts;
379        }
380        // @ts-ignore
381        return param;
382    }
383    //初始化cpu check状态
384    initDefaultConfig(): void {
385        if (this.isCreateCpu) {
386            if (Utils.getInstance().getWinCpuCount() === CORE_NUM) {
387                this.smallCores = [...SMALL_CPU_NUM];
388                this.midCores = [...MID_CPU_NUM12];
389                this.largeCores = [...LARGE_CPU_NUM12];
390            } else {
391                this.smallCores = [];
392                this.midCores = [];
393                this.largeCores = [];
394            }
395        }
396    }
397
398    //初始化分组
399    initGroupFn(arr: unknown): void {
400        let info = [...this.bufferGroupMap.values()].reduce((acc, val) => acc.concat(val), []);
401        // @ts-ignore
402        let flag = arr.filter((item: unknown) => info.includes(item)).length > 0;
403        // @ts-ignore
404        if (arr.length && arr.length > 1 && !flag) {
405            let len = this.groupContentDiv!.childNodes.length + 1;
406            // @ts-ignore
407            let str = arr.join(',');
408            // @ts-ignore
409            this.bufferGroupMap.set(`group${len}`, arr);
410            this.groupContentDiv!.innerHTML += `<div style="border-bottom: 1px solid black;">group${len}:${str}</div>`;
411        }
412    }
413    //更新Group Setting Cpu列的展示与操作状态
414    getGroupTableLine(str?: string): void {
415        this.isCreateGroup = false;
416        this.cpuTbl!.innerHTML = '';
417        this.creatCpuHeaderDiv();
418        let bufferInfo = [...this.bufferGroupMap.values()].reduce((acc, val) => acc.concat(val), []);
419        let switchArr = Object.values(CORE_JSON).flat();
420        for (let i = 0; i < Utils.getInstance().getWinCpuCount(); i++) {
421            let obj = {
422                cpu: i,
423                isCheck: Utils.getInstance().getWinCpuCount() === CORE_NUM && str !== 'cut' && this.isReset ? switchArr.includes(i) : bufferInfo.includes(i),
424                disabled:
425                    Utils.getInstance().getWinCpuCount() === CORE_NUM && str !== 'cut' && this.isReset ?
426                        !(switchArr.includes(i)) :
427                        !([...this.smallCores, ...this.midCores, ...this.largeCores].includes(i))
428            };
429            this.creatGroupLineDIv(obj);
430        }
431    }
432    //创建cpu表头
433    creatCpuHeaderDiv(): void {
434        let cpuIdLine = document.createElement('div');
435        cpuIdLine.className = 'core_line';
436        cpuIdLine.style.fontWeight = 'bold';
437        cpuIdLine.style.fontStyle = '12px';
438        cpuIdLine.textContent = 'Cpu';
439        cpuIdLine.style.textAlign = 'center';
440        this.cpuTbl?.append(...[cpuIdLine]);
441    }
442    //Gropu容器中新增Tbl的cpu Line值
443    creatGroupLineDIv(obj: unknown): void {
444        // @ts-ignore
445        let id = `${obj.cpu}`.toString();
446        let checkBoxId = `box${id}`;
447        // 创建一个包裹div来容纳checkbox和cpuLine
448        let wrapperDiv = document.createElement('div');
449        wrapperDiv.className = 'check-content';
450        wrapperDiv.id = checkBoxId;
451        // 创建checkBox实例
452        let checkBox: LitCheckBox = new LitCheckBox();
453        // @ts-ignore
454        checkBox.checked = obj.isCheck;
455        // @ts-ignore
456        checkBox.disabled = obj.disabled;
457        checkBox.setAttribute('not-close', '');
458        // 添加事件监听器到checkBox
459        checkBox.addEventListener('change', (e: unknown) => {
460            // @ts-ignore
461            checkBox.checked = e.detail.checked;
462            // @ts-ignore
463            this.bottomFilterEl!.canUpdateCheckList(e.detail.checked, this.addGroupArr, obj.cpu);
464        });
465        wrapperDiv.appendChild(checkBox);
466        // 创建cpuLine div
467        let cpuLine = document.createElement('div');
468        // @ts-ignore
469        cpuLine.textContent = obj.cpu + '';
470        cpuLine.style.textAlign = 'center';
471        cpuLine.style.fontWeight = 'normal';
472        // 将cpuLine也添加到wrapperDiv
473        wrapperDiv.appendChild(cpuLine);
474        this.cpuTbl!.append(wrapperDiv);
475    }
476    //回调函数,首次插入DOM时执行的初始化回调
477    connectedCallback(): void {
478        new ResizeObserver(() => {
479            if (this.parentElement?.clientHeight !== 0) {
480                // @ts-ignore
481                this.parallelTable!.shadowRoot!.querySelector('.table')!.style.height = `${this.parentElement!.clientHeight - 31}px`;
482                this.parallelTable?.reMeauseHeight();
483                if (this.parentElement!.clientHeight >= 0 && this.parentElement!.clientHeight <= 31) {
484                    this.bottomFilterEl!.style.display = 'none';
485                } else {
486                    this.bottomFilterEl!.style.display = 'flex';
487                }
488            }
489        }).observe(this.parentElement!);
490    }
491    initHtml(): string {
492        return MtSettingHtml;
493    }
494}
495