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