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