Add new Splay benchmark to the V8 benchmark suite and remove

the unused parts (most) of the Prototype library from raytrace.js.
Review URL: http://codereview.chromium.org/115227

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1910 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2009-05-12 08:23:11 +00:00
parent bde19c7365
commit 1a54dd0197
10 changed files with 471 additions and 2530 deletions

View File

@ -40,3 +40,15 @@ pages where it occurs and the number of times it is executed while
loading each page. Finally the literal letters in the data are
encoded using ROT13 in a way that does not affect how the regexps
match their input.
Changes from Version 3 to Version 4
===================================
The Splay benchmark is a newcomer in version 4. It manipulates a
splay tree by adding and removing data nodes, thus exercising the
memory management subsystem of the JavaScript engine.
Furthermore, all the unused parts of the Prototype library were
removed from the RayTrace benchmark. This does not affect the running
of the benchmark.

View File

@ -31,10 +31,15 @@
// A benchmark has a name (string) and a function that will be run to
// do the performance measurement.
function Benchmark(name, run) {
// do the performance measurement. The optional setup and tearDown
// arguments are functions that will be invoked before and after
// running the benchmark, but the running time of these functions will
// not be accounted for in the benchmark score.
function Benchmark(name, run, setup, tearDown) {
this.name = name;
this.run = run;
this.Setup = setup ? setup : function() { };
this.TearDown = tearDown ? tearDown : function() { };
}
@ -73,7 +78,7 @@ BenchmarkSuite.suites = [];
// Scores are not comparable across versions. Bump the version if
// you're making changes that will affect that scores, e.g. if you add
// a new benchmark or change an existing one.
BenchmarkSuite.version = '3';
BenchmarkSuite.version = '4';
// To make the benchmark results predictable, we replace Math.random
@ -114,7 +119,7 @@ BenchmarkSuite.RunSuites = function(runner) {
continuation = suite.RunStep(runner);
}
if (continuation && typeof window != 'undefined' && window.setTimeout) {
window.setTimeout(RunStep, 100);
window.setTimeout(RunStep, 25);
return;
}
}
@ -194,7 +199,7 @@ BenchmarkSuite.prototype.NotifyError = function(error) {
// Runs a single benchmark for at least a second and computes the
// average time it takes to run a single iteration.
BenchmarkSuite.prototype.RunSingle = function(benchmark) {
BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) {
var elapsed = 0;
var start = new Date();
for (var n = 0; elapsed < 1000; n++) {
@ -216,18 +221,45 @@ BenchmarkSuite.prototype.RunStep = function(runner) {
var length = this.benchmarks.length;
var index = 0;
var suite = this;
function RunNext() {
// Run the setup, the actual benchmark, and the tear down in three
// separate steps to allow the framework to yield between any of the
// steps.
function RunNextSetup() {
if (index < length) {
try {
suite.RunSingle(suite.benchmarks[index++]);
suite.benchmarks[index].Setup();
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNext;
return RunNextBenchmark;
}
suite.NotifyResult();
return null;
}
return RunNext();
function RunNextBenchmark() {
try {
suite.RunSingleBenchmark(suite.benchmarks[index]);
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNextTearDown;
}
function RunNextTearDown() {
try {
suite.benchmarks[index++].TearDown();
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNextSetup;
}
// Start out running the setup.
return RunNextSetup();
}

View File

@ -4682,4 +4682,3 @@ function RunBenchmark(name, count, run, warn) {
}
var BgL_runzd2benchmarkzd2 = RunBenchmark;

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,20 @@ the benchmark suite.
</p>
<div class="subtitle"><h3>Version 4 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v4/run.html">link</a>)</h3></div>
<p>The <i>Splay</i> benchmark is a newcomer in version 4. It
manipulates a splay tree by adding and removing data nodes, thus
exercising the memory management subsystem of the JavaScript engine.
</p>
<p>
Furthermore, all the unused parts of the Prototype library were
removed from the RayTrace benchmark. This does not affect the running
of the benchmark.
</p>
<div class="subtitle"><h3>Version 3 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v3/run.html">link</a>)</h3></div>
<p>Version 3 adds a new benchmark, <i>RegExp</i>. The RegExp
@ -32,9 +46,10 @@ encoded using ROT13 in a way that does not affect how the regexps
match their input.
</p>
<div class="subtitle"><h3>Version 2 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v2/run.html">link</a>)</h3></div>
<p>For version 2 the crypto benchmark was fixed. Previously, the
<p>For version 2 the Crypto benchmark was fixed. Previously, the
decryption stage was given plaintext as input, which resulted in an
error. Now, the decryption stage is given the output of the
encryption stage as input. The result is checked against the original
@ -49,6 +64,7 @@ results of their calculations. This is to avoid accidentally
obtaining scores that are the result of an incorrect JavaScript engine
optimization.</p>
<div class="subtitle"><h3>Version 1 (<a href="http://v8.googlecode.com/svn/data/benchmarks/v1/run.html">link</a>)</h3></div>
<p>Initial release.</p>

View File

@ -8,6 +8,7 @@
<script type="text/javascript" src="raytrace.js"></script>
<script type="text/javascript" src="earley-boyer.js"></script>
<script type="text/javascript" src="regexp.js"></script>
<script type="text/javascript" src="splay.js"></script>
<link type="text/css" rel="stylesheet" href="style.css"></link>
<script type="text/javascript">
var completed = 0;
@ -72,12 +73,13 @@ higher scores means better performance: <em>Bigger is better!</em>
<ul>
<li><b>Richards</b><br/>OS kernel simulation benchmark, originally written in BCPL by Martin Richards (<i>539 lines</i>).</li>
<li><b>DeltaBlue</b><br/>One-way constraint solver, originally written in Smalltalk by John Maloney and Mario Wolczko (<i>880 lines</i>).</li>
<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1689 lines</i>).</li>
<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>3418 lines</i>).</li>
<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4682 lines</i>).</li>
<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1698 lines</i>).</li>
<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>935 lines</i>).</li>
<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4685 lines</i>).</li>
<li><b>RegExp</b><br/>Regular expression benchmark generated by extracting regular expression operations from 50 of the most popular web pages
(<i>4758 lines</i>).
(<i>1614 lines</i>).
</li>
<li><b>Splay</b><br/>Data manipulation benchmark that deals with splay trees and exercises the automatic memory management subsystem (<i>378 lines</i>).</li>
</ul>
<p>
@ -90,7 +92,7 @@ the <a href="http://v8.googlecode.com/svn/data/benchmarks/current/revisions.html
</td><td style="text-align: center">
<div class="run">
<div id="status" style="text-align: center; margin-top: 60px; font-size: 120%; font-weight: bold;">Starting...</div>
<div id="status" style="text-align: center; margin-top: 50px; font-size: 120%; font-weight: bold;">Starting...</div>
<div style="text-align: left; margin: 30px 0 0 90px;" id="results">
<div>
</div>

View File

@ -33,6 +33,7 @@ load('crypto.js');
load('raytrace.js');
load('earley-boyer.js');
load('regexp.js');
load('splay.js');
var success = true;

378
benchmarks/splay.js Normal file
View File

@ -0,0 +1,378 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This benchmark is based on a JavaScript log processing module used
// by the V8 profiler to generate execution time profiles for runs of
// JavaScript applications, and it effectively measures how fast the
// JavaScript engine is at allocating nodes and reclaiming the memory
// used for old nodes. Because of the way splay trees work, the engine
// also has to deal with a lot of changes to the large tree object
// graph.
var Splay = new BenchmarkSuite('Splay', 126125, [
new Benchmark("Splay", SplayRun, SplaySetup, SplayTearDown)
]);
// Configuration.
var kSplayTreeSize = 8000;
var kSplayTreeModifications = 80;
var kSplayTreePayloadDepth = 5;
var splayTree = null;
function GeneratePayloadTree(depth, key) {
if (depth == 0) {
return {
array : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
string : 'String for key ' + key + ' in leaf node'
};
} else {
return {
left: GeneratePayloadTree(depth - 1, key),
right: GeneratePayloadTree(depth - 1, key)
};
}
}
function GenerateKey() {
// The benchmark framework guarantees that Math.random is
// deterministic; see base.js.
return Math.random();
}
function InsertNewNode() {
// Insert new node with a unique key.
var key;
do {
key = GenerateKey();
} while (splayTree.find(key) != null);
splayTree.insert(key, GeneratePayloadTree(kSplayTreePayloadDepth, key));
return key;
}
function SplaySetup() {
splayTree = new SplayTree();
for (var i = 0; i < kSplayTreeSize; i++) InsertNewNode();
}
function SplayTearDown() {
// Allow the garbage collector to reclaim the memory
// used by the splay tree no matter how we exit the
// tear down function.
var keys = splayTree.exportKeys();
splayTree = null;
// Verify that the splay tree has the right size.
var length = keys.length;
if (length != kSplayTreeSize) {
throw new Error("Splay tree has wrong size");
}
// Verify that the splay tree has sorted, unique keys.
for (var i = 0; i < length - 1; i++) {
if (keys[i] >= keys[i + 1]) {
throw new Error("Splay tree not sorted");
}
}
}
function SplayRun() {
// Replace a few nodes in the splay tree.
for (var i = 0; i < kSplayTreeModifications; i++) {
var key = InsertNewNode();
var greatest = splayTree.findGreatestLessThan(key);
if (greatest == null) splayTree.remove(key);
else splayTree.remove(greatest.key);
}
}
/**
* Constructs a Splay tree. A splay tree is a self-balancing binary
* search tree with the additional property that recently accessed
* elements are quick to access again. It performs basic operations
* such as insertion, look-up and removal in O(log(n)) amortized time.
*
* @constructor
*/
function SplayTree() {
};
/**
* Pointer to the root node of the tree.
*
* @type {SplayTree.Node}
* @private
*/
SplayTree.prototype.root_ = null;
/**
* @return {boolean} Whether the tree is empty.
*/
SplayTree.prototype.isEmpty = function() {
return !this.root_;
};
/**
* Inserts a node into the tree with the specified key and value if
* the tree does not already contain a node with the specified key. If
* the value is inserted, it becomes the root of the tree.
*
* @param {number} key Key to insert into the tree.
* @param {*} value Value to insert into the tree.
*/
SplayTree.prototype.insert = function(key, value) {
if (this.isEmpty()) {
this.root_ = new SplayTree.Node(key, value);
return;
}
// Splay on the key to move the last node on the search path for
// the key to the root of the tree.
this.splay_(key);
if (this.root_.key == key) {
return;
}
var node = new SplayTree.Node(key, value);
if (key > this.root_.key) {
node.left = this.root_;
node.right = this.root_.right;
this.root_.right = null;
} else {
node.right = this.root_;
node.left = this.root_.left;
this.root_.left = null;
}
this.root_ = node;
};
/**
* Removes a node with the specified key from the tree if the tree
* contains a node with this key. The removed node is returned. If the
* key is not found, an exception is thrown.
*
* @param {number} key Key to find and remove from the tree.
* @return {SplayTree.Node} The removed node.
*/
SplayTree.prototype.remove = function(key) {
if (this.isEmpty()) {
throw Error('Key not found: ' + key);
}
this.splay_(key);
if (this.root_.key != key) {
throw Error('Key not found: ' + key);
}
var removed = this.root_;
if (!this.root_.left) {
this.root_ = this.root_.right;
} else {
var right = this.root_.right;
this.root_ = this.root_.left;
// Splay to make sure that the new root has an empty right child.
this.splay_(key);
// Insert the original right child as the right child of the new
// root.
this.root_.right = right;
}
return removed;
};
/**
* Returns the node having the specified key or null if the tree doesn't contain
* a node with the specified key.
*
* @param {number} key Key to find in the tree.
* @return {SplayTree.Node} Node having the specified key.
*/
SplayTree.prototype.find = function(key) {
if (this.isEmpty()) {
return null;
}
this.splay_(key);
return this.root_.key == key ? this.root_ : null;
};
/**
* @return {SplayTree.Node} Node having the maximum key value that
* is less or equal to the specified key value.
*/
SplayTree.prototype.findGreatestLessThan = function(key) {
if (this.isEmpty()) {
return null;
}
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
this.splay_(key);
// Now the result is either the root node or the greatest node in
// the left subtree.
if (this.root_.key <= key) {
return this.root_;
} else if (this.root_.left) {
return this.findMax(this.root_.left);
} else {
return null;
}
};
/**
* @return {Array<*>} An array containing all the keys of tree's nodes.
*/
SplayTree.prototype.exportKeys = function() {
var result = [];
if (!this.isEmpty()) {
this.root_.traverse_(function(node) { result.push(node.key); });
}
return result;
};
/**
* Perform the splay operation for the given key. Moves the node with
* the given key to the top of the tree. If no node has the given
* key, the last node on the search path is moved to the top of the
* tree. This is the simplified top-down splaying algorithm from:
* "Self-adjusting Binary Search Trees" by Sleator and Tarjan
*
* @param {number} key Key to splay the tree on.
* @private
*/
SplayTree.prototype.splay_ = function(key) {
if (this.isEmpty()) {
return;
}
// Create a dummy node. The use of the dummy node is a bit
// counter-intuitive: The right child of the dummy node will hold
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
var dummy, left, right;
dummy = left = right = new SplayTree.Node(null, null);
var current = this.root_;
while (true) {
if (key < current.key) {
if (!current.left) {
break;
}
if (key < current.left.key) {
// Rotate right.
var tmp = current.left;
current.left = tmp.right;
tmp.right = current;
current = tmp;
if (!current.left) {
break;
}
}
// Link right.
right.left = current;
right = current;
current = current.left;
} else if (key > current.key) {
if (!current.right) {
break;
}
if (key > current.right.key) {
// Rotate left.
var tmp = current.right;
current.right = tmp.left;
tmp.left = current;
current = tmp;
if (!current.right) {
break;
}
}
// Link left.
left.right = current;
left = current;
current = current.right;
} else {
break;
}
}
// Assemble.
left.right = current.left;
right.left = current.right;
current.left = dummy.right;
current.right = dummy.left;
this.root_ = current;
};
/**
* Constructs a Splay tree node.
*
* @param {number} key Key.
* @param {*} value Value.
*/
SplayTree.Node = function(key, value) {
this.key = key;
this.value = value;
};
/**
* @type {SplayTree.Node}
*/
SplayTree.Node.prototype.left = null;
/**
* @type {SplayTree.Node}
*/
SplayTree.Node.prototype.right = null;
/**
* Performs an ordered traversal of the subtree starting at
* this SplayTree.Node.
*
* @param {function(SplayTree.Node)} f Visitor function.
* @private
*/
SplayTree.Node.prototype.traverse_ = function(f) {
var current = this;
while (current) {
var left = current.left;
if (left) left.traverse_(f);
f(current);
current = current.right;
}
};