[js-perf] Add benchmarks for capturing and serializing stack traces

This CL adds two sets of benchmarks. The first measures the effort
needed to walk the stack and create the data structure stored in
Error.stack, while the second measures the serialization of that
Error.stack data structure into a string.

R=petermarshall@chromium.org, yangguo@chromium.org

Bug: v8:8742
Change-Id: Ie7b86da5621cb186a036a3ec99692ec4d2048fba
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1505614
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60176}
This commit is contained in:
Simon Zünd 2019-03-11 07:58:29 +01:00 committed by Commit Bot
parent 25865f0609
commit b7aa85fe00
4 changed files with 180 additions and 0 deletions

View File

@ -1461,6 +1461,24 @@
"tests": [
{"name": "NumberToString"}
]
},
{
"name": "StackTrace",
"path": ["StackTrace"],
"main": "run.js",
"flags": ["--allow-natives-syntax"],
"resources": ["capture.js", "serialize.js"],
"results_regexp": "^%s\\-StackTrace\\(Score\\): (.+)$",
"tests": [
{"name": "Simple-Capture-Error"},
{"name": "Custom-Capture-Error"},
{"name": "Inline-Capture-Error"},
{"name": "Recursive-Capture-Error"},
{"name": "Simple-Serialize-Error.stack"},
{"name": "Custom-Serialize-Error.stack"},
{"name": "Inline-Serialize-Error.stack"},
{"name": "Recursive-Serialize-Error.stack"}
]
}
]
}

View File

@ -0,0 +1,51 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
function Simple() {
new Error("Simple Error");
}
class CustomError extends Error {};
function Custom() {
new CustomError("Custom Error");
}
function Inline() {
function Inner() {
new Error("Error from inlined function!");
}
function Middle() { Inner(); }
function Outer() { Middle(); }
Outer();
Outer();
%OptimizeFunctionOnNextCall(Outer);
Outer();
}
const kInitialRecursionValue = 10;
function Recursive() {
function StepOne(val) {
if (val <= 0) return new Error("Error in StepOne!");
StepTwo(val - 3);
StepTwo(val - 4);
}
function StepTwo(val) {
if (val <= 0) return new Error("Error in StepTwo!");
StepOne(val - 1);
StepOne(val - 2);
}
StepOne(kInitialRecursionValue);
}
createSuite('Simple-Capture-Error', 1000, Simple, () => {});
createSuite('Custom-Capture-Error', 1000, Custom, () => {});
createSuite('Inline-Capture-Error', 1000, Inline, () => {});
createSuite('Recursive-Capture-Error', 1000, Recursive, () => {});
})();

View File

@ -0,0 +1,25 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
load('../base.js');
load('serialize.js');
load('capture.js');
function PrintResult(name, result) {
print(name + '-StackTrace(Score): ' + result);
}
function PrintStep(name) {}
function PrintError(name, error) {
PrintResult(name, error);
}
BenchmarkSuite.config.doWarmup = undefined;
BenchmarkSuite.config.doDeterministic = undefined;
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyError: PrintError,
NotifyStep: PrintStep });

View File

@ -0,0 +1,86 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
const kErrorCount = 100000;
let errorsCreatedBySetup;
function CreateErrors(fn) {
counter = 0;
errorsCreatedBySetup = [];
for (let i = 0; i < kErrorCount; ++i) {
errorsCreatedBySetup[i] = fn();
}
}
function SimpleSetup() {
CreateErrors(() => new Error("Simple Error"));
}
class CustomError extends Error {};
function CustomSetup() {
CreateErrors(() => new CustomError("Custom Error"));
}
function InlineSetup() {
function Inner() {
return new Error("Throwing from inlined function!");
}
function Middle() { return Inner(); }
function Outer() { return Middle(); }
Outer();
Outer();
%OptimizeFunctionOnNextCall(Outer);
Outer();
CreateErrors(() => Outer());
}
const kInitialRecursionValue = 12;
function RecursiveSetup() {
counter = 0;
errorsCreatedBySetup = [];
function StepOne(val) {
if (val <= 0) {
errorsCreatedBySetup.push(new Error("Error in StepOne!"));
return;
}
StepTwo(val - 3);
StepTwo(val - 4);
}
function StepTwo(val) {
if (val <= 0) {
errorsCreatedBySetup.push(new Error("Error in StepTwo!"));
return;
}
StepOne(val - 1);
StepOne(val - 2);
}
while (errorsCreatedBySetup.length < kErrorCount) {
StepOne(kInitialRecursionValue);
}
}
let counter;
function SerializeStack() {
if (counter < errorsCreatedBySetup.length) {
// Trigger serialization by accessing Error.stack.
%FlattenString(errorsCreatedBySetup[counter++].stack);
} else {
// The counter is reset after hitting the end, although
// Error.stack is cached at this point.
counter = 0;
}
}
createSuite('Simple-Serialize-Error.stack', 1000, SerializeStack, SimpleSetup);
createSuite('Custom-Serialize-Error.stack', 1000, SerializeStack, CustomSetup);
createSuite('Inline-Serialize-Error.stack', 1000, SerializeStack, InlineSetup);
createSuite('Recursive-Serialize-Error.stack', 1000, SerializeStack, RecursiveSetup);
})();