• 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 { SpSystemTrace } from '../SpSystemTrace';
17import { TraceRow } from '../trace/base/TraceRow';
18import { procedurePool } from '../../database/Procedure';
19import { EBPFChartStruct, EBPFRender } from '../../database/ui-worker/ProcedureWorkerEBPF';
20import { ColorUtils } from '../trace/base/ColorUtils';
21import { Utils } from '../trace/base/Utils';
22import { renders } from '../../database/ui-worker/ProcedureWorker';
23import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
24import { diskIoSender, fileSysVMSender, fileSystemSender } from '../../database/data-trafic/EBPFSender';
25import { hasFileSysData } from '../../database/sql/Memory.sql';
26import { getDiskIOProcess } from '../../database/sql/SqlLite.sql';
27
28export class SpEBPFChart {
29  private trace: SpSystemTrace;
30
31  constructor(trace: SpSystemTrace) {
32    this.trace = trace;
33  }
34
35  async init(): Promise<void> {
36    let sys = await hasFileSysData();
37    if (sys.length > 0) {
38      //@ts-ignore
39      let fsCount = sys[0].fsCount ?? 0;
40      //@ts-ignore
41      let vmCount = sys[0].vmCount ?? 0;
42      //@ts-ignore
43      let ioCount = sys[0].ioCount ?? 0;
44      if (sys && sys.length > 0 && (fsCount > 0 || vmCount > 0 || ioCount > 0)) {
45        let folder = await this.initFolder();
46        await this.initFileCallchain();
47        if (fsCount > 0) {
48          await this.initLogicalRead(folder);
49          await this.initLogicalWrite(folder);
50        }
51        if (vmCount > 0) {
52          await this.initVirtualMemoryTrace(folder);
53        }
54        if (ioCount > 0) {
55          await this.initDiskIOLatency(folder);
56          await this.initProcessDiskIOLatency(folder);
57        }
58      }
59    }
60  }
61
62  async initFileCallchain(): Promise<unknown> {
63    return new Promise<unknown>((resolve, reject) => {
64      procedurePool.submitWithName('logic0', 'fileSystem-init', null, undefined, (res: unknown) => {
65        resolve(res);
66      });
67    });
68  }
69
70  //@ts-ignore
71  async initFolder(): Promise<TraceRow<unknown>> {
72    let fsFolder = TraceRow.skeleton();
73    fsFolder.rowId = 'FileSystem';
74    fsFolder.index = 0;
75    fsFolder.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM_GROUP;
76    fsFolder.rowParentId = '';
77    fsFolder.style.height = '40px';
78    fsFolder.folder = true;
79    fsFolder.name = 'EBPF'; /* & I/O Latency */
80    fsFolder.addTemplateTypes('HiEBpf');
81    fsFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler;
82    fsFolder.selectChangeHandler = this.trace.selectChangeHandler; //@ts-ignore
83    fsFolder.supplierFrame = (): Promise<Array<unknown>> => new Promise<Array<unknown>>((resolve) => resolve([]));
84    fsFolder.onThreadHandler = (useCache): void => {
85      fsFolder.canvasSave(this.trace.canvasPanelCtx!);
86      if (fsFolder.expansion) {
87        // @ts-ignore
88        this.trace.canvasPanelCtx?.clearRect(0, 0, fsFolder.frame.width, fsFolder.frame.height);
89      } else {
90        (renders.empty as EmptyRender).renderMainThread(
91          {
92            context: this.trace.canvasPanelCtx,
93            useCache: useCache,
94            type: '',
95          },
96          fsFolder
97        );
98      }
99      fsFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
100    };
101    this.trace.rowsEL?.appendChild(fsFolder);
102    return fsFolder;
103  }
104
105  //@ts-ignore
106  async initLogicalRead(folder: TraceRow<unknown>): Promise<void> {
107    let logicalReadRow = TraceRow.skeleton<EBPFChartStruct>();
108    logicalReadRow.rowId = 'FileSystemLogicalRead';
109    logicalReadRow.index = 1;
110    logicalReadRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
111    logicalReadRow.rowParentId = folder.rowId;
112    logicalReadRow.rowHidden = !folder.expansion;
113    logicalReadRow.style.height = '40px';
114    logicalReadRow.setAttribute('children', '');
115    logicalReadRow.name = 'FileSystem Logical Read';
116    logicalReadRow.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
117      const res = await fileSystemSender(2, TraceRow.range?.scale || 50, logicalReadRow);
118      return res;
119    };
120    logicalReadRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
121    logicalReadRow.selectChangeHandler = this.trace.selectChangeHandler;
122    logicalReadRow.focusHandler = (): void => this.focusHandler(logicalReadRow);
123    logicalReadRow.findHoverStruct = (): void => {
124      EBPFChartStruct.hoverEBPFStruct = logicalReadRow.getHoverStruct(false);
125    };
126    logicalReadRow.onThreadHandler = (useCache): void => {
127      let context: CanvasRenderingContext2D;
128      if (logicalReadRow.currentContext) {
129        context = logicalReadRow.currentContext;
130      } else {
131        context = logicalReadRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
132      }
133      logicalReadRow.canvasSave(context);
134      //@ts-ignore
135      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
136        {
137          context: context,
138          useCache: useCache,
139          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-read`,
140          chartColor: ColorUtils.MD_PALETTE[0],
141        },
142        logicalReadRow
143      );
144      logicalReadRow.canvasRestore(context, this.trace);
145    };
146    folder.addChildTraceRow(logicalReadRow);
147  }
148
149  //@ts-ignore
150  async initLogicalWrite(folder: TraceRow<unknown>): Promise<void> {
151    let logicalWriteRow = TraceRow.skeleton<EBPFChartStruct>();
152    logicalWriteRow.rowId = 'FileSystemLogicalWrite';
153    logicalWriteRow.index = 2;
154    logicalWriteRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
155    logicalWriteRow.rowParentId = folder.rowId;
156    logicalWriteRow.rowHidden = !folder.expansion;
157    logicalWriteRow.style.height = '40px';
158    logicalWriteRow.setAttribute('children', '');
159    logicalWriteRow.name = 'FileSystem Logical Write';
160    logicalWriteRow.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
161      const res = await fileSystemSender(3, TraceRow.range?.scale || 50, logicalWriteRow);
162      return res;
163    };
164    logicalWriteRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
165    logicalWriteRow.selectChangeHandler = this.trace.selectChangeHandler;
166    logicalWriteRow.focusHandler = (): void => this.focusHandler(logicalWriteRow);
167    logicalWriteRow.findHoverStruct = (): void => {
168      EBPFChartStruct.hoverEBPFStruct = logicalWriteRow.getHoverStruct(false);
169    };
170    logicalWriteRow.onThreadHandler = (useCache): void => {
171      let context: CanvasRenderingContext2D;
172      if (logicalWriteRow.currentContext) {
173        context = logicalWriteRow.currentContext;
174      } else {
175        context = logicalWriteRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
176      }
177      logicalWriteRow.canvasSave(context);
178      //@ts-ignore
179      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
180        {
181          context: context,
182          useCache: useCache,
183          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-write`,
184          chartColor: ColorUtils.MD_PALETTE[8],
185        },
186        logicalWriteRow
187      );
188      logicalWriteRow.canvasRestore(context, this.trace);
189    };
190    folder.addChildTraceRow(logicalWriteRow);
191  }
192
193  //@ts-ignore
194  async initDiskIOLatency(folder: TraceRow<unknown>): Promise<void> {
195    let diskIoRow = TraceRow.skeleton<EBPFChartStruct>();
196    diskIoRow.rowId = 'FileSystemDiskIOLatency';
197    diskIoRow.index = 4;
198    diskIoRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
199    diskIoRow.rowParentId = folder.rowId;
200    diskIoRow.rowHidden = !folder.expansion;
201    diskIoRow.style.height = '40px';
202    diskIoRow.style.width = '100%';
203    diskIoRow.setAttribute('children', '');
204    diskIoRow.name = 'Disk I/O Latency';
205    diskIoRow.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
206      const res = await diskIoSender(true, 0, [1, 2, 3, 4], TraceRow.range?.scale || 50, diskIoRow);
207      return res;
208    };
209    diskIoRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
210    diskIoRow.selectChangeHandler = this.trace.selectChangeHandler;
211    diskIoRow.focusHandler = (): void => this.focusHandler(diskIoRow);
212    diskIoRow.findHoverStruct = (): void => {
213      EBPFChartStruct.hoverEBPFStruct = diskIoRow.getHoverStruct(false);
214    };
215    diskIoRow.onThreadHandler = (useCache): void => {
216      let context: CanvasRenderingContext2D;
217      if (diskIoRow.currentContext) {
218        context = diskIoRow.currentContext;
219      } else {
220        context = diskIoRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
221      }
222      diskIoRow.canvasSave(context);
223      //@ts-ignore
224      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
225        {
226          context: context,
227          useCache: useCache,
228          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io`,
229          chartColor: ColorUtils.MD_PALETTE[0],
230        },
231        diskIoRow
232      );
233      diskIoRow.canvasRestore(context, this.trace);
234    };
235    folder.addChildTraceRow(diskIoRow);
236  }
237
238  //@ts-ignore
239  initProcessDiskIOLatencyRead(i: number, folder: TraceRow<unknown>, process: unknown): TraceRow<EBPFChartStruct> {
240    let rowRead = TraceRow.skeleton<EBPFChartStruct>();
241    rowRead.index = 5 + 2 * i; //@ts-ignore
242    rowRead.rowId = `FileSystemDiskIOLatency-read-${process.ipid}`;
243    rowRead.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
244    rowRead.rowParentId = folder.rowId;
245    rowRead.rowHidden = !folder.expansion;
246    rowRead.style.height = '40px';
247    rowRead.style.width = '100%';
248    rowRead.setAttribute('children', ''); //@ts-ignore
249    rowRead.name = `${process.name ?? 'Process'}(${process.ipid}) Max Read Latency`;
250    rowRead.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
251      //@ts-ignore
252      const res = await diskIoSender(false, process.ipid, [1, 3], TraceRow.range?.scale || 50, rowRead);
253      return res;
254    };
255    rowRead.favoriteChangeHandler = this.trace.favoriteChangeHandler;
256    rowRead.selectChangeHandler = this.trace.selectChangeHandler;
257    rowRead.focusHandler = (): void => this.focusHandler(rowRead);
258    rowRead.findHoverStruct = (): void => {
259      EBPFChartStruct.hoverEBPFStruct = rowRead.getHoverStruct(false);
260    };
261    rowRead.onThreadHandler = (useCache): void => {
262      let context: CanvasRenderingContext2D;
263      if (rowRead.currentContext) {
264        context = rowRead.currentContext;
265      } else {
266        context = rowRead.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
267      }
268      rowRead.canvasSave(context);
269      //@ts-ignore
270      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
271        {
272          context: context,
273          useCache: useCache, //@ts-ignore
274          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-read-${process.pid}`,
275          chartColor: ColorUtils.MD_PALETTE[0],
276        },
277        rowRead
278      );
279      rowRead.canvasRestore(context, this.trace);
280    };
281    return rowRead;
282  }
283
284  //@ts-ignore
285  private initProcessDiskIOWrite(i: number, folder: TraceRow<unknown>, process: unknown): TraceRow<EBPFChartStruct> {
286    let rowWrite = TraceRow.skeleton<EBPFChartStruct>();
287    rowWrite.index = 5 + 2 * i + 1; //@ts-ignore
288    rowWrite.rowId = `FileSystemDiskIOLatency-write-${process.ipid}`;
289    rowWrite.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
290    rowWrite.rowParentId = folder.rowId;
291    rowWrite.rowHidden = !folder.expansion;
292    rowWrite.style.height = '40px';
293    rowWrite.style.width = '100%';
294    rowWrite.setAttribute('children', ''); //@ts-ignore
295    rowWrite.name = `${process.name ?? 'Process'}(${process.pid}) Max Write Latency`;
296    rowWrite.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
297      //@ts-ignore
298      const res = await diskIoSender(false, process.ipid, [2, 4], TraceRow.range?.scale || 50, rowWrite);
299      return res;
300    };
301    rowWrite.favoriteChangeHandler = this.trace.favoriteChangeHandler;
302    rowWrite.selectChangeHandler = this.trace.selectChangeHandler;
303    rowWrite.focusHandler = (): void => this.focusHandler(rowWrite);
304    rowWrite.findHoverStruct = (): void => {
305      EBPFChartStruct.hoverEBPFStruct = rowWrite.getHoverStruct(false);
306    };
307    rowWrite.onThreadHandler = (useCache): void => {
308      let context: CanvasRenderingContext2D;
309      if (rowWrite.currentContext) {
310        context = rowWrite.currentContext;
311      } else {
312        context = rowWrite.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
313      }
314      rowWrite.canvasSave(context);
315      //@ts-ignore
316      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
317        {
318          context: context,
319          useCache: useCache, //@ts-ignore
320          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-write-${process.pid}`,
321          chartColor: ColorUtils.MD_PALETTE[8],
322        },
323        rowWrite
324      );
325      rowWrite.canvasRestore(context, this.trace);
326    };
327    return rowWrite;
328  }
329
330  //@ts-ignore
331  async initProcessDiskIOLatency(folder: TraceRow<unknown>): Promise<void> {
332    let processes = (await getDiskIOProcess()) || [];
333    for (let i = 0, len = processes.length; i < len; i++) {
334      let process = processes[i];
335      const rowRead = this.initProcessDiskIOLatencyRead(i, folder, process);
336      folder.addChildTraceRow(rowRead);
337      const rowWrite = this.initProcessDiskIOWrite(i, folder, process);
338      folder.addChildTraceRow(rowWrite);
339    }
340  }
341
342  //@ts-ignore
343  async initVirtualMemoryTrace(folder: TraceRow<unknown>): Promise<void> {
344    let vmTraceRow = TraceRow.skeleton<EBPFChartStruct>();
345    vmTraceRow.rowId = 'FileSystemVirtualMemory';
346    vmTraceRow.index = 3;
347    vmTraceRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
348    vmTraceRow.rowParentId = folder.rowId;
349    vmTraceRow.rowHidden = !folder.expansion;
350    vmTraceRow.rangeSelect = true;
351    vmTraceRow.style.height = '40px';
352    vmTraceRow.style.width = '100%';
353    vmTraceRow.setAttribute('children', '');
354    vmTraceRow.name = 'Page Fault Trace';
355    vmTraceRow.supplierFrame = async (): Promise<EBPFChartStruct[]> => {
356      const res = await fileSysVMSender(TraceRow.range?.scale || 50, vmTraceRow);
357      return res;
358    };
359    vmTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
360    vmTraceRow.selectChangeHandler = this.trace.selectChangeHandler;
361    vmTraceRow.focusHandler = (): void => this.focusHandler(vmTraceRow);
362    vmTraceRow.findHoverStruct = (): void => {
363      EBPFChartStruct.hoverEBPFStruct = vmTraceRow.getHoverStruct(false, false, 'size');
364    };
365    vmTraceRow.onThreadHandler = (useCache): void => {
366      let context: CanvasRenderingContext2D;
367      if (vmTraceRow.currentContext) {
368        context = vmTraceRow.currentContext;
369      } else {
370        context = vmTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
371      }
372      vmTraceRow.canvasSave(context);
373      //@ts-ignore
374      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as EBPFRender).renderMainThread(
375        {
376          context: context,
377          useCache: useCache,
378          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-virtual-memory`,
379          chartColor: ColorUtils.MD_PALETTE[0],
380        },
381        vmTraceRow
382      );
383      vmTraceRow.canvasRestore(context, this.trace);
384    };
385    folder.addChildTraceRow(vmTraceRow);
386  }
387
388  focusHandler(row: TraceRow<EBPFChartStruct>): void {
389    let num = 0;
390    let tip = '';
391    if (EBPFChartStruct.hoverEBPFStruct) {
392      num = EBPFChartStruct.hoverEBPFStruct.size ?? 0;
393      let group10Ms = EBPFChartStruct.hoverEBPFStruct.group10Ms ?? false;
394      if (row.rowId!.startsWith('FileSystemDiskIOLatency')) {
395        if (num > 0) {
396          let tipStr = Utils.getProbablyTime(num);
397          if (group10Ms) {
398            tip = `<span>${tipStr} (10.00ms)</span>`;
399          } else {
400            tip = `<span>${tipStr}</span>`;
401          }
402        }
403      } else {
404        if (num > 0) {
405          if (group10Ms) {
406            tip = `<span>${num} (10.00ms)</span>`;
407          } else {
408            tip = `<span>${num}</span>`;
409          }
410        }
411      }
412    }
413    this.trace?.displayTip(row, EBPFChartStruct.hoverEBPFStruct, tip);
414  }
415}
416