• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {calcOffsetInVMCage} from '../js/helper.mjs';
6import {DOM, FileReader,} from '../js/web-api-helper.mjs';
7
8import {kSpaceNames} from './space-categories.mjs';
9
10class TraceLogParseHelper {
11  static re_gc_header = /(Before|After) GC:\d/;
12  static re_page_info =
13      /\{owner:.+,address:.+,size:.+,allocated_bytes:.+,wasted_memory:.+\}/;
14  static re_owner = /(?<=owner:)[a-z_]+_space/;
15  static re_address = /(?<=address:)0x[a-f0-9]+(?=,)/;
16  static re_size = /(?<=size:)\d+(?=,)/;
17  static re_allocated_bytes = /(?<=allocated_bytes:)\d+(?=,)/;
18  static re_wasted_memory = /(?<=wasted_memory:)\d+(?=})/;
19
20  static matchGCHeader(content) {
21    return this.re_gc_header.test(content);
22  }
23
24  static matchPageInfo(content) {
25    return this.re_page_info.test(content);
26  }
27
28  static parsePageInfo(content) {
29    const owner = this.re_owner.exec(content)[0];
30    const address =
31        calcOffsetInVMCage(BigInt(this.re_address.exec(content)[0], 16));
32    const size = parseInt(this.re_size.exec(content)[0]);
33    const allocated_bytes = parseInt(this.re_allocated_bytes.exec(content)[0]);
34    const wasted_memory = parseInt(this.re_wasted_memory.exec(content)[0]);
35    const info = [
36      owner,
37      address,
38      address + size,
39      allocated_bytes,
40      wasted_memory,
41    ];
42    return info;
43  }
44
45  // Create a empty snapshot.
46  static createSnapShotData() {
47    let snapshot = {header: null, data: {}};
48    for (let space_name of kSpaceNames) {
49      snapshot.data[space_name] = [];
50    }
51    return snapshot;
52  }
53
54  static createModelFromV8TraceFile(contents) {
55    let snapshots = [];
56    let snapshot = this.createSnapShotData();
57
58    // Fill data info a snapshot, then push it into snapshots.
59    for (let content of contents) {
60      if (this.matchGCHeader(content)) {
61        if (snapshot.header != null) {
62          snapshots.push(snapshot);
63        }
64        snapshot = this.createSnapShotData();
65        snapshot.header = content;
66        continue;
67      }
68
69      if (this.matchPageInfo(content)) {
70        let pageinfo = this.parsePageInfo(content);
71        try {
72          snapshot.data[pageinfo[0]].push(pageinfo);
73        } catch (e) {
74          console.error(e);
75        }
76      }
77    }
78    // EOL, push the last.
79    if (snapshot.header != null) {
80      snapshots.push(snapshot);
81    }
82    return snapshots;
83  }
84}
85
86DOM.defineCustomElement('../js/log-file-reader', 'trace-file-reader',
87                        (templateText) =>
88                            class TraceFileReader extends FileReader {
89  constructor() {
90    super(templateText);
91    this.fullDataFromFile = '';
92    this.addEventListener('fileuploadchunk', (e) => this.handleLoadChunk(e));
93
94    this.addEventListener('fileuploadend', (e) => this.handleLoadEnd(e));
95  }
96
97  handleLoadChunk(event) {
98    this.fullDataFromFile += event.detail;
99  }
100
101  handleLoadEnd(event) {
102    let contents = this.fullDataFromFile.split('\n');
103    let snapshots = TraceLogParseHelper.createModelFromV8TraceFile(contents);
104    this.dispatchEvent(new CustomEvent('change', {
105      bubbles: true,
106      composed: true,
107      detail: snapshots,
108    }));
109  }
110});
111