Commit 0e9f9aab authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[system-analyzer] Use Streams API for log files

Use the Streams API for file Blobs, instead of FileReader, to allow
large files to be loaded in chunks.

Change-Id: I241e0daff3f9c3d491dde2f3e8e52ea2236f05be
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2953286
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75095}
parent fdf0a3a7
...@@ -34,7 +34,8 @@ const result = doWork(); ...@@ -34,7 +34,8 @@ const result = doWork();
const logString = d8.log.getAndStop(); const logString = d8.log.getAndStop();
const processor = new Processor(); const processor = new Processor();
processor.processString(logString); processor.processChunk(logString);
processor.finalize();
const maps = processor.mapTimeline; const maps = processor.mapTimeline;
const ics = processor.icTimeline; const ics = processor.icTimeline;
......
...@@ -49,6 +49,8 @@ class App { ...@@ -49,6 +49,8 @@ class App {
}; };
this._view.logFileReader.addEventListener( this._view.logFileReader.addEventListener(
'fileuploadstart', (e) => this.handleFileUploadStart(e)); 'fileuploadstart', (e) => this.handleFileUploadStart(e));
this._view.logFileReader.addEventListener(
'fileuploadchunk', (e) => this.handleFileUploadChunk(e));
this._view.logFileReader.addEventListener( this._view.logFileReader.addEventListener(
'fileuploadend', (e) => this.handleFileUploadEnd(e)); 'fileuploadend', (e) => this.handleFileUploadEnd(e));
this._startupPromise = this.runAsyncInitialize(); this._startupPromise = this.runAsyncInitialize();
...@@ -307,20 +309,28 @@ class App { ...@@ -307,20 +309,28 @@ class App {
this._view.toolTip.content = content; this._view.toolTip.content = content;
} }
restartApp() {
this._state = new State();
this._navigation = new Navigation(this._state, this._view);
}
handleFileUploadStart(e) { handleFileUploadStart(e) {
this.restartApp(); this.restartApp();
$('#container').className = 'initial'; $('#container').className = 'initial';
this._processor = new Processor();
} }
restartApp() { handleFileUploadChunk(e) {
this._state = new State(); this._processor.processChunk(e.detail);
this._navigation = new Navigation(this._state, this._view);
} }
async handleFileUploadEnd(e) { async handleFileUploadEnd(e) {
await this._startupPromise;
try { try {
const processor = new Processor(e.detail); const processor = this._processor;
processor.finalize();
await this._startupPromise;
this._state.profile = processor.profile; this._state.profile = processor.profile;
const mapTimeline = processor.mapTimeline; const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline; const icTimeline = processor.icTimeline;
......
...@@ -25,9 +25,10 @@ export class Processor extends LogReader { ...@@ -25,9 +25,10 @@ export class Processor extends LogReader {
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/; _formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
_lastTimestamp = 0; _lastTimestamp = 0;
_lastCodeLogEntry; _lastCodeLogEntry;
_chunkRemainder = '';
MAJOR_VERSION = 7; MAJOR_VERSION = 7;
MINOR_VERSION = 6; MINOR_VERSION = 6;
constructor(logString) { constructor() {
super(); super();
const propertyICParser = [ const propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString, parseInt, parseInt, parseInt, parseInt, parseString, parseString,
...@@ -136,7 +137,6 @@ export class Processor extends LogReader { ...@@ -136,7 +137,6 @@ export class Processor extends LogReader {
processor: this.processApiEvent processor: this.processApiEvent
}, },
}; };
if (logString) this.processString(logString);
} }
printError(str) { printError(str) {
...@@ -144,26 +144,29 @@ export class Processor extends LogReader { ...@@ -144,26 +144,29 @@ export class Processor extends LogReader {
throw str throw str
} }
processString(string) { processChunk(chunk) {
let end = string.length; let end = chunk.length;
let current = 0; let current = 0;
let next = 0; let next = 0;
let line; let line;
let i = 0;
let entry;
try { try {
while (current < end) { while (current < end) {
next = string.indexOf('\n', current); next = chunk.indexOf('\n', current);
if (next === -1) break; if (next === -1) {
i++; this._chunkRemainder = chunk.substring(current);
line = string.substring(current, next); break;
}
line = chunk.substring(current, next);
if (this._chunkRemainder) {
line = this._chunkRemainder + line;
this._chunkRemainder = '';
}
current = next + 1; current = next + 1;
this.processLogLine(line); this.processLogLine(line);
} }
} catch (e) { } catch (e) {
console.error(`Error occurred during parsing, trying to continue: ${e}`); console.error(`Error occurred during parsing, trying to continue: ${e}`);
} }
this.finalize();
} }
processLogFile(fileName) { processLogFile(fileName) {
......
...@@ -58,27 +58,33 @@ DOM.defineCustomElement('view/log-file-reader', ...@@ -58,27 +58,33 @@ DOM.defineCustomElement('view/log-file-reader',
return this.$('#root'); return this.$('#root');
} }
readFile(file) { async readFile(file) {
if (!file) { if (!file) {
this.error = 'Failed to load file.'; this.error = 'Failed to load file.';
return; return;
} }
this.fileReader.blur(); this.fileReader.blur();
this.root.className = 'loading'; this.root.className = 'loading';
const reader = new FileReader();
reader.onload = (e) => this.handleFileLoad(e, file);
// Delay the loading a bit to allow for CSS animations to happen.
setTimeout(() => reader.readAsText(file), 0);
}
handleFileLoad(e, file) { const stream = file.stream().pipeThrough(new TextDecoderStream());
const chunk = e.target.result; const reader = stream.getReader();
let chunk, readerDone;
do {
const readResult = await reader.read();
chunk = readResult.value;
readerDone = readResult.done;
if (!chunk) continue;
this.dispatchEvent(new CustomEvent('fileuploadchunk', {
bubbles: true,
composed: true,
detail: chunk,
}));
} while (!readerDone);
this._updateLabel(`Finished loading '${file.name}'.`); this._updateLabel(`Finished loading '${file.name}'.`);
this.dispatchEvent(new CustomEvent('fileuploadend', { this.dispatchEvent(
bubbles: true, new CustomEvent('fileuploadend', {bubbles: true, composed: true}));
composed: true,
detail: chunk,
}));
this.root.className = 'done'; this.root.className = 'done';
} }
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment