• 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.js';
17import { TraceRow } from '../trace/base/TraceRow.js';
18import { procedurePool } from '../../database/Procedure.js';
19import {
20  getDiskIOLatencyChartDataByProcess,
21  getDiskIOProcess,
22  getFileSysChartDataByType,
23  getFileSysVirtualMemoryChartData,
24  hasFileSysData,
25} from '../../database/SqlLite.js';
26import { FileSysChartStruct, FileSystemRender } from '../../database/ui-worker/ProcedureWorkerFileSystem.js';
27import { ColorUtils } from '../trace/base/ColorUtils.js';
28import { Utils } from '../trace/base/Utils.js';
29import { renders } from '../../database/ui-worker/ProcedureWorker.js';
30import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js';
31
32export class SpFileSystemChart {
33  private trace: SpSystemTrace;
34
35  constructor(trace: SpSystemTrace) {
36    this.trace = trace;
37  }
38
39  async init() {
40    let sys = await hasFileSysData();
41    if (sys.length > 0) {
42      let fsCount = sys[0]['fsCount'] ?? 0;
43      let vmCount = sys[0]['vmCount'] ?? 0;
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() {
64    return new Promise<any>((resolve, reject) => {
65      procedurePool.submitWithName('logic0', 'fileSystem-init', SpSystemTrace.DATA_DICT, undefined, (res: any) => {
66        resolve(res);
67      });
68    });
69  }
70
71  async initFolder(): Promise<TraceRow<any>> {
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.favoriteChangeHandler = this.trace.favoriteChangeHandler;
81    fsFolder.selectChangeHandler = this.trace.selectChangeHandler;
82    fsFolder.supplier = () => new Promise<Array<any>>((resolve) => resolve([]));
83    fsFolder.onThreadHandler = (useCache) => {
84      fsFolder.canvasSave(this.trace.canvasPanelCtx!);
85      if (fsFolder.expansion) {
86        this.trace.canvasPanelCtx?.clearRect(0, 0, fsFolder.frame.width, fsFolder.frame.height);
87      } else {
88        (renders['empty'] as EmptyRender).renderMainThread(
89          {
90            context: this.trace.canvasPanelCtx,
91            useCache: useCache,
92            type: ``,
93          },
94          fsFolder
95        );
96      }
97      fsFolder.canvasRestore(this.trace.canvasPanelCtx!);
98    };
99    this.trace.rowsEL?.appendChild(fsFolder);
100    return fsFolder;
101  }
102
103  async initLogicalRead(folder: TraceRow<any>) {
104    let logicalReadRow = TraceRow.skeleton<FileSysChartStruct>();
105    logicalReadRow.rowId = `FileSystemLogicalRead`;
106    logicalReadRow.index = 1;
107    logicalReadRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
108    logicalReadRow.rowParentId = folder.rowId;
109    logicalReadRow.rowHidden = !folder.expansion;
110    logicalReadRow.style.height = '40px';
111    logicalReadRow.setAttribute('children', '');
112    logicalReadRow.name = `FileSystem Logical Read`;
113    logicalReadRow.supplier = () => getFileSysChartDataByType(2);
114    logicalReadRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
115    logicalReadRow.selectChangeHandler = this.trace.selectChangeHandler;
116    logicalReadRow.focusHandler = () => this.focusHandler(logicalReadRow);
117    logicalReadRow.onThreadHandler = (useCache) => {
118      let context = logicalReadRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
119      logicalReadRow.canvasSave(context);
120      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
121        {
122          context: context,
123          useCache: useCache,
124          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-read`,
125          chartColor: ColorUtils.MD_PALETTE[0],
126        },
127        logicalReadRow
128      );
129      logicalReadRow.canvasRestore(context);
130    };
131    folder.addChildTraceRow(logicalReadRow);
132  }
133
134  async initLogicalWrite(folder: TraceRow<any>) {
135    let logicalWriteRow = TraceRow.skeleton<FileSysChartStruct>();
136    logicalWriteRow.rowId = `FileSystemLogicalWrite`;
137    logicalWriteRow.index = 2;
138    logicalWriteRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
139    logicalWriteRow.rowParentId = folder.rowId;
140    logicalWriteRow.rowHidden = !folder.expansion;
141    logicalWriteRow.style.height = '40px';
142    logicalWriteRow.setAttribute('children', '');
143    logicalWriteRow.name = `FileSystem Logical Write`;
144    logicalWriteRow.supplier = () => getFileSysChartDataByType(3);
145    logicalWriteRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
146    logicalWriteRow.selectChangeHandler = this.trace.selectChangeHandler;
147    logicalWriteRow.focusHandler = () => this.focusHandler(logicalWriteRow);
148    logicalWriteRow.onThreadHandler = (useCache) => {
149      let context = logicalWriteRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
150      logicalWriteRow.canvasSave(context);
151      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
152        {
153          context: context,
154          useCache: useCache,
155          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-write`,
156          chartColor: ColorUtils.MD_PALETTE[8],
157        },
158        logicalWriteRow
159      );
160      logicalWriteRow.canvasRestore(context);
161    };
162    folder.addChildTraceRow(logicalWriteRow);
163  }
164
165  async initDiskIOLatency(folder: TraceRow<any>) {
166    let diskIoRow = TraceRow.skeleton<FileSysChartStruct>();
167    diskIoRow.rowId = `FileSystemDiskIOLatency`;
168    diskIoRow.index = 4;
169    diskIoRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
170    diskIoRow.rowParentId = folder.rowId;
171    diskIoRow.rowHidden = !folder.expansion;
172    diskIoRow.style.height = '40px';
173    diskIoRow.style.width = `100%`;
174    diskIoRow.setAttribute('children', '');
175    diskIoRow.name = `Disk I/O Latency`;
176    diskIoRow.supplier = () => getDiskIOLatencyChartDataByProcess(true, 0, [1, 2, 3, 4]);
177    diskIoRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
178    diskIoRow.selectChangeHandler = this.trace.selectChangeHandler;
179    diskIoRow.focusHandler = () => this.focusHandler(diskIoRow);
180    diskIoRow.onThreadHandler = (useCache) => {
181      let context = diskIoRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
182      diskIoRow.canvasSave(context);
183      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
184        {
185          context: context,
186          useCache: useCache,
187          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io`,
188          chartColor: ColorUtils.MD_PALETTE[0],
189        },
190        diskIoRow
191      );
192      diskIoRow.canvasRestore(context);
193    };
194    folder.addChildTraceRow(diskIoRow);
195  }
196
197  async initProcessDiskIOLatency(folder: TraceRow<any>) {
198    let processes = (await getDiskIOProcess()) || [];
199    for (let i = 0, len = processes.length; i < len; i++) {
200      let process = processes[i];
201      let rowRead = TraceRow.skeleton<FileSysChartStruct>();
202      rowRead.index = 5 + 2 * i;
203      rowRead.rowId = `FileSystemDiskIOLatency-read-${process['ipid']}`;
204      rowRead.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
205      rowRead.rowParentId = folder.rowId;
206      rowRead.rowHidden = !folder.expansion;
207      rowRead.style.height = '40px';
208      rowRead.style.width = `100%`;
209      rowRead.setAttribute('children', '');
210      rowRead.name = `${process['name'] ?? 'Process'}(${process['pid']}) Max Read Latency`;
211      rowRead.supplier = () => getDiskIOLatencyChartDataByProcess(false, process['ipid'], [1, 3]);
212      rowRead.favoriteChangeHandler = this.trace.favoriteChangeHandler;
213      rowRead.selectChangeHandler = this.trace.selectChangeHandler;
214      rowRead.focusHandler = () => this.focusHandler(rowRead);
215      rowRead.onThreadHandler = (useCache) => {
216        let context = rowRead.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
217        rowRead.canvasSave(context);
218        (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
219          {
220            context: context,
221            useCache: useCache,
222            type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-read-${process['pid']}`,
223            chartColor: ColorUtils.MD_PALETTE[0],
224          },
225          rowRead
226        );
227        rowRead.canvasRestore(context);
228      };
229      folder.addChildTraceRow(rowRead);
230      let rowWrite = TraceRow.skeleton<FileSysChartStruct>();
231      rowWrite.index = 5 + 2 * i + 1;
232      rowWrite.rowId = `FileSystemDiskIOLatency-write-${process['ipid']}`;
233      rowWrite.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
234      rowWrite.rowParentId = folder.rowId;
235      rowWrite.rowHidden = !folder.expansion;
236      rowWrite.style.height = '40px';
237      rowWrite.style.width = `100%`;
238      rowWrite.setAttribute('children', '');
239      rowWrite.name = `${process['name'] ?? 'Process'}(${process['pid']}) Max Write Latency`;
240      rowWrite.supplier = () => getDiskIOLatencyChartDataByProcess(false, process['ipid'], [2, 4]);
241      rowWrite.favoriteChangeHandler = this.trace.favoriteChangeHandler;
242      rowWrite.selectChangeHandler = this.trace.selectChangeHandler;
243      rowWrite.focusHandler = () => this.focusHandler(rowWrite);
244      rowWrite.onThreadHandler = (useCache) => {
245        let context = rowWrite.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
246        rowWrite.canvasSave(context);
247        (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
248          {
249            context: context,
250            useCache: useCache,
251            type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-write-${process['pid']}`,
252            chartColor: ColorUtils.MD_PALETTE[8],
253          },
254          rowWrite
255        );
256        rowWrite.canvasRestore(context);
257      };
258      folder.addChildTraceRow(rowWrite);
259    }
260  }
261
262  async initVirtualMemoryTrace(folder: TraceRow<any>) {
263    let vmTraceRow = TraceRow.skeleton<FileSysChartStruct>();
264    vmTraceRow.rowId = `FileSystemVirtualMemory`;
265    vmTraceRow.index = 3;
266    vmTraceRow.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
267    vmTraceRow.rowParentId = folder.rowId;
268    vmTraceRow.rowHidden = !folder.expansion;
269    vmTraceRow.rangeSelect = true;
270    vmTraceRow.style.height = '40px';
271    vmTraceRow.style.width = `100%`;
272    vmTraceRow.setAttribute('children', '');
273    vmTraceRow.name = `Page Fault Trace`;
274    vmTraceRow.supplier = () => getFileSysVirtualMemoryChartData();
275    vmTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
276    vmTraceRow.selectChangeHandler = this.trace.selectChangeHandler;
277    vmTraceRow.focusHandler = () => this.focusHandler(vmTraceRow);
278    vmTraceRow.onThreadHandler = (useCache) => {
279      let context = vmTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
280      vmTraceRow.canvasSave(context);
281      (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread(
282        {
283          context: context,
284          useCache: useCache,
285          type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-virtual-memory`,
286          chartColor: ColorUtils.MD_PALETTE[0],
287        },
288        vmTraceRow
289      );
290      vmTraceRow.canvasRestore(context);
291    };
292    folder.addChildTraceRow(vmTraceRow);
293  }
294
295  focusHandler(row: TraceRow<FileSysChartStruct>) {
296    let num = 0;
297    let tip = '';
298    if (FileSysChartStruct.hoverFileSysStruct) {
299      num = FileSysChartStruct.hoverFileSysStruct.size ?? 0;
300      let group10Ms = FileSysChartStruct.hoverFileSysStruct.group10Ms ?? false;
301      if (row.rowId!.startsWith('FileSystemDiskIOLatency')) {
302        if (num > 0) {
303          let tipStr = Utils.getProbablyTime(num);
304          if (group10Ms) {
305            tip = `<span>${tipStr} (10.00ms)</span>`;
306          } else {
307            tip = `<span>${tipStr}</span>`;
308          }
309        }
310      } else {
311        if (num > 0) {
312          if (group10Ms) {
313            tip = `<span>${num} (10.00ms)</span>`;
314          } else {
315            tip = `<span>${num}</span>`;
316          }
317        }
318      }
319    }
320    this.trace?.displayTip(row, FileSysChartStruct.hoverFileSysStruct, tip);
321  }
322}
323