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