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:
64
browser/components/extensions/ParseCppFiltSymbols-worker.js
Normal file
64
browser/components/extensions/ParseCppFiltSymbols-worker.js
Normal 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()});
|
||||
}
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -16,6 +16,7 @@ EXTRA_COMPONENTS += [
|
||||
EXTRA_JS_MODULES += [
|
||||
'ExtensionPopups.jsm',
|
||||
'ParseBreakpadSymbols-worker.js',
|
||||
'ParseCppFiltSymbols-worker.js',
|
||||
'ParseNMSymbols-worker.js',
|
||||
'ParseSymbols.jsm',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user