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();
const logString = d8.log.getAndStop();
const processor = new Processor();
processor.processString(logString);
processor.processChunk(logString);
processor.finalize();
const maps = processor.mapTimeline;
const ics = processor.icTimeline;
......
......@@ -49,6 +49,8 @@ class App {
};
this._view.logFileReader.addEventListener(
'fileuploadstart', (e) => this.handleFileUploadStart(e));
this._view.logFileReader.addEventListener(
'fileuploadchunk', (e) => this.handleFileUploadChunk(e));
this._view.logFileReader.addEventListener(
'fileuploadend', (e) => this.handleFileUploadEnd(e));
this._startupPromise = this.runAsyncInitialize();
......@@ -307,20 +309,28 @@ class App {
this._view.toolTip.content = content;
}
restartApp() {
this._state = new State();
this._navigation = new Navigation(this._state, this._view);
}
handleFileUploadStart(e) {
this.restartApp();
$('#container').className = 'initial';
this._processor = new Processor();
}
restartApp() {
this._state = new State();
this._navigation = new Navigation(this._state, this._view);
handleFileUploadChunk(e) {
this._processor.processChunk(e.detail);
}
async handleFileUploadEnd(e) {
await this._startupPromise;
try {
const processor = new Processor(e.detail);
const processor = this._processor;
processor.finalize();
await this._startupPromise;
this._state.profile = processor.profile;
const mapTimeline = processor.mapTimeline;
const icTimeline = processor.icTimeline;
......
......@@ -25,9 +25,10 @@ export class Processor extends LogReader {
_formatPCRegexp = /(.*):[0-9]+:[0-9]+$/;
_lastTimestamp = 0;
_lastCodeLogEntry;
_chunkRemainder = '';
MAJOR_VERSION = 7;
MINOR_VERSION = 6;
constructor(logString) {
constructor() {
super();
const propertyICParser = [
parseInt, parseInt, parseInt, parseInt, parseString, parseString,
......@@ -136,7 +137,6 @@ export class Processor extends LogReader {
processor: this.processApiEvent
},
};
if (logString) this.processString(logString);
}
printError(str) {
......@@ -144,26 +144,29 @@ export class Processor extends LogReader {
throw str
}
processString(string) {
let end = string.length;
processChunk(chunk) {
let end = chunk.length;
let current = 0;
let next = 0;
let line;
let i = 0;
let entry;
try {
while (current < end) {
next = string.indexOf('\n', current);
if (next === -1) break;
i++;
line = string.substring(current, next);
next = chunk.indexOf('\n', current);
if (next === -1) {
this._chunkRemainder = chunk.substring(current);
break;
}
line = chunk.substring(current, next);
if (this._chunkRemainder) {
line = this._chunkRemainder + line;
this._chunkRemainder = '';
}
current = next + 1;
this.processLogLine(line);
}
} catch (e) {
console.error(`Error occurred during parsing, trying to continue: ${e}`);
}
this.finalize();
}
processLogFile(fileName) {
......
......@@ -58,27 +58,33 @@ DOM.defineCustomElement('view/log-file-reader',
return this.$('#root');
}
readFile(file) {
async readFile(file) {
if (!file) {
this.error = 'Failed to load file.';
return;
}
this.fileReader.blur();
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 chunk = e.target.result;
const stream = file.stream().pipeThrough(new TextDecoderStream());
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.dispatchEvent(new CustomEvent('fileuploadend', {
bubbles: true,
composed: true,
detail: chunk,
}));
this.dispatchEvent(
new CustomEvent('fileuploadend', {bubbles: true, composed: true}));
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