Bug 1362786 - (3) Run CppFiltParser in worker r=kmag

Pulls out the CppFiltParser work into a worker to run in the
background and avoid the jank induced by the final
convertSymsMapToExpectedSymFormat call.

Profiling shows that after this change there is virtually no
jank when asking the geckoProfiler API for symbols.

MozReview-Commit-ID: CAKMvjLa4dl
This commit is contained in:
Doug Thayer
2017-07-21 14:13:37 -07:00
parent 72f38fe98d
commit 9ca534b98d
4 changed files with 91 additions and 34 deletions

View File

@@ -0,0 +1,64 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* eslint-env worker */
"use strict";
importScripts("resource:///modules/ParseSymbols.jsm");
class WorkerCppFiltParser {
constructor(length) {
this._decoder = new TextDecoder();
this._index = 0;
this._approximateLength = 0;
this._results = new Array(length);
}
consume(arrayBuffer) {
const data = this._decoder.decode(arrayBuffer, {stream: true});
const lineRegex = /.*\n?/g;
const buffer = this._currentLine + data;
let match;
while ((match = lineRegex.exec(buffer))) {
let [line] = match;
if (line[line.length - 1] === "\n") {
this._processLine(line);
} else {
this._currentLine = line;
break;
}
}
}
finish() {
this._processLine(this._currentLine);
return {symsArray: this._results, approximateLength: this._approximateLength};
}
_processLine(line) {
const trimmed = line.trimRight();
this._approximateLength += trimmed.length;
this._results[this._index++] = trimmed;
}
}
let cppFiltParser;
onmessage = async e => {
try {
if (!cppFiltParser) {
cppFiltParser = new WorkerCppFiltParser();
}
if (e.data.finish) {
const {symsArray, approximateLength} = cppFiltParser.finish();
const result = ParseSymbols.convertSymsArrayToExpectedSymFormat(symsArray, approximateLength);
postMessage({result}, result.map(r => r.buffer));
close();
} else {
cppFiltParser.consume(e.data.buffer);
}
} catch (error) {
postMessage({error: error.toString()});
}
};

View File

@@ -44,6 +44,12 @@ function convertSymsMapToExpectedSymFormat(syms, approximateSymLength) {
return [new Uint32Array(addresses), index, buffer];
}
function convertSymsArrayToExpectedSymFormat(symsArray, approximateSymLength) {
const {index, buffer} =
convertStringArrayToUint8BufferWithIndex(symsArray, approximateSymLength);
return [index, buffer];
}
function convertSymsMapToDemanglerFormat(syms) {
const addresses = Array.from(syms.keys());
addresses.sort((a, b) => a - b);
@@ -57,5 +63,6 @@ function convertSymsMapToDemanglerFormat(syms) {
var ParseSymbols = {
convertSymsMapToExpectedSymFormat,
convertSymsArrayToExpectedSymFormat,
convertSymsMapToDemanglerFormat,
};

View File

@@ -65,36 +65,28 @@ class NMParser {
}
class CppFiltParser {
constructor(length) {
this._decoder = new TextDecoder();
this._index = 0;
this._results = new Array(length);
constructor() {
this._worker = new ChromeWorker("resource://app/modules/ParseCppFiltSymbols-worker.js");
}
consume(arrayBuffer) {
const data = this._decoder.decode(arrayBuffer, {stream: true});
const lineRegex = /.*\n?/g;
const buffer = this._currentLine + data;
let match;
while ((match = lineRegex.exec(buffer))) {
let [line] = match;
if (line[line.length - 1] === "\n") {
this._processLine(line);
} else {
this._currentLine = line;
break;
}
}
consume(buffer) {
this._worker.postMessage({buffer}, [buffer]);
}
finish() {
this._processLine(this._currentLine);
return this._results;
}
_processLine(line) {
this._results[this._index++] = line.trimRight();
const promise = new Promise((resolve, reject) => {
this._worker.onmessage = (e) => {
if (e.data.error) {
reject(e.data.error);
} else {
resolve(e.data.result);
}
};
});
this._worker.postMessage({
finish: true,
});
return promise;
}
}
@@ -140,20 +132,13 @@ const getSymbolsFromNM = async function(path, arch) {
return result;
}
const syms = new Map();
const [addresses, symbolsJoinedBuffer] = result;
const decoder = new TextDecoder();
const symbolsJoined = decoder.decode(symbolsJoinedBuffer);
const demangler = new CppFiltParser(addresses.length);
await spawnProcess("c++filt", [], data => demangler.consume(data), symbolsJoined);
const newSymbols = demangler.finish();
let approximateLength = 0;
for (let [i, symbol] of newSymbols.entries()) {
approximateLength += symbol.length;
syms.set(addresses[i], symbol);
}
return ParseSymbols.convertSymsMapToExpectedSymFormat(syms, approximateLength);
const [newIndex, newBuffer] = await demangler.finish();
return [addresses, newIndex, newBuffer];
};
const pathComponentsForSymbolFile = (debugName, breakpadId) => {

View File

@@ -16,6 +16,7 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES += [
'ExtensionPopups.jsm',
'ParseBreakpadSymbols-worker.js',
'ParseCppFiltSymbols-worker.js',
'ParseNMSymbols-worker.js',
'ParseSymbols.jsm',
]