cleaning up (1)

This commit is contained in:
DadaMonad
2014-12-14 17:00:02 +00:00
parent 9b582fc795
commit 7696864841
50 changed files with 9302 additions and 6 deletions

View File

@@ -0,0 +1,183 @@
/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
(function(global) {
'use strict';
function now() {
return global.performance && typeof performance.now == 'function' ?
performance.now() : Date.now();
}
function checkpoint() {
if (global.Platform &&
typeof Platform.performMicrotaskCheckpoint == 'function') {
Platform.performMicrotaskCheckpoint();
}
}
// TODO(rafaelw): Add simple Promise polyfill for IE.
var TESTING_TICKS = 400;
var TICKS_PER_FRAME = 16;
var MAX_RUNS = 50;
function Benchmark(testingTicks, ticksPerFrame, maxRuns) {
this.testingTicks = testingTicks || TESTING_TICKS;
this.ticksPerFrame = ticksPerFrame || TICKS_PER_FRAME;
this.maxRuns = maxRuns || 50;
this.average = 0;
}
Benchmark.prototype = {
// Abstract API
setup: function(variation) {},
test: function() {
throw Error('Not test function found');
},
cleanup: function() {},
runOne: function(variation) {
this.setup(variation);
var before = now();
this.test(variation);
var self = this;
return Promise.resolve().then(function() {
checkpoint();
var after = now();
self.cleanup(variation);
return after - before;
});
},
runMany: function(count, variation) {
var self = this;
return new Promise(function(fulfill) {
var total = 0;
function next(time) {
if (!count) {
fulfill(total);
return;
}
self.runOne(variation).then(function(time) {
count--;
total += time;
next();
});
}
requestAnimationFrame(next);
});
},
runVariation: function(variation, reportFn) {
var self = this;
reportFn = reportFn || function() {}
return new Promise(function(fulfill) {
self.runMany(3, variation).then(function(time) {
return time/3;
}).then(function(estimate) {
var runsPerFrame = Math.ceil(self.ticksPerFrame / estimate);
var frames = Math.ceil(self.testingTicks / self.ticksPerFrame);
var maxFrames = Math.ceil(self.maxRuns / runsPerFrame);
frames = Math.min(frames, maxFrames);
var count = 0;
var total = 0;
function next() {
if (!frames) {
self.average = total / count;
self.dispose();
fulfill(self.average);
return;
}
self.runMany(runsPerFrame, variation).then(function(time) {
frames--;
total += time;
count += runsPerFrame;
reportFn(variation, count);
next();
});
}
next();
});
});
},
run: function(variations, reportFn) {
if (!Array.isArray(variations)) {
return this.runVariation(variations, reportFn);
}
var self = this;
variations = variations.slice();
return new Promise(function(fulfill) {
var results = [];
function next() {
if (!variations.length) {
fulfill(results);
return;
}
var variation = variations.shift();
self.runVariation(variation, reportFn).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
};
function all(benchmarks, variations, statusFn) {
return new Promise(function(fulfill) {
var results = [];
var current;
function next() {
current = benchmarks.shift();
if (!current) {
fulfill(results);
return;
}
function update(variation, runs) {
statusFn(current, variation, runs);
}
current.run(variations, update).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
global.Benchmark = Benchmark;
global.Benchmark.all = all;
})(this);

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
var console = {
log: print
};
var requestAnimationFrame = function(callback) {
callback();
}
recordCount = 0;
var alert = print;
function reportResults(times) {
console.log(JSON.stringify(times));
}
function reportStatus(b, variation, count) {
console.log(b.objectCount + ' objects, ' + count + ' runs.');
}
var objectCounts = [ 4000, 8000, 16000 ];
var benchmarks = [];
objectCounts.forEach(function(objectCount, i) {
benchmarks.push(
new SetupPathBenchmark('', objectCount));
});
Benchmark.all(benchmarks, 0, reportStatus).then(reportResults);

View File

@@ -0,0 +1,181 @@
<html>
<!--
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<head>
<title>Observation Benchmarks</title>
<meta charset="utf-8">
<script src="../src/observe.js"></script>
<script src="chartjs/Chart.js"></script>
<script src="benchmark.js"></script>
<script src="observation_benchmark.js"></script>
<style>
* {
font-family: arial, helvetica, sans-serif;
font-weight: 400;
}
body {
margin: 0;
padding: 0;
background-color: rgba(0, 0, 0, .1);
}
</style>
</head>
<body>
<h1>Observation Benchmarks</h1>
<select id="benchmarkSelect">
<option>ObjectBenchmark</option>
<option>SetupObjectBenchmark</option>
<option>ArrayBenchmark</option>
<option>SetupArrayBenchmark</option>
<option>PathBenchmark</option>
<option>SetupPathBenchmark</option>
</select>
<select id="configSelect">
</select>
<button id="go">Run Benchmarks</button>
<span>Object Count: </span>
<input id="objectCountInput" style="width: 200px" value="4000, 8000, 16000, 32000"><br>
<span>Mutation Count: </span>
<input id="mutationCountInput" style="width: 200px" value="0, 100, 200, 400, 800, 1600"><br>
<br>
<span id="status"></span>
<section style="width: 100%">
<article>
<div style="display:inline-block; padding-bottom: 20px">
Times in ms
</div>
<div style="display:inline-block">
<canvas id="times" width="800" height="400"></canvas>
</div>
<div style="display:inline-block">
<ul id="legendList">
</ul>
</div>
</article>
</section>
<h3 style="margin-left: 440px">Object Set Size</h3>
<script>
var benchmark;
var goButton = document.getElementById('go');
var objectCountInput = document.getElementById('objectCountInput');
var mutationCountInput = document.getElementById('mutationCountInput');
var statusSpan = document.getElementById('status');
var timesCanvas = document.getElementById('times');
var benchmarkSelect = document.getElementById('benchmarkSelect');
var configSelect = document.getElementById('configSelect');
function changeBenchmark() {
benchmark = window[benchmarkSelect.value];
configSelect.textContent = '';
benchmark.configs.forEach(function(config) {
var option = document.createElement('option');
option.textContent = config;
configSelect.appendChild(option);
});
document.title = benchmarkSelect.value;
}
benchmarkSelect.addEventListener('change', changeBenchmark);
changeBenchmark();
var ul = document.getElementById('legendList');
var colors = [
[0, 0, 255],
[138,43,226],
[165,42,42],
[100,149,237],
[220,20,60],
[184,134,11]
].map(function(rgb) {
return 'rgba(' + rgb.join(',') + ',.7)';
});
goButton.addEventListener('click', function() {
goButton.disabled = true;
goButton.textContent = 'Running...';
ul.textContent = '';
var objectCounts = objectCountInput.value.split(',').map(function(val) {
return Number(val);
});
var mutationCounts = mutationCountInput.value.split(',').map(function(val) {
return Number(val);
});
mutationCounts.forEach(function(count, i) {
var li = document.createElement('li');
li.textContent = count + ' mutations.'
li.style.color = colors[i];
ul.appendChild(li);
});
var results = [];
function benchmarkComplete(times) {
timesArray = [];
var index = 0;
mutationCounts.forEach(function(mutationCount, i) {
timesArray.push([]);
objectCounts.forEach(function(objectCount, j) {
timesArray[i][j] = times[j][i];
});
});
timesCanvas.height = 400;
timesCanvas.width = 800;
timesCanvas.setAttribute('style', '');
var ctx = timesCanvas.getContext("2d");
new Chart(ctx).Line({
labels: objectCounts,
datasets: timesArray.map(function(times, i) {
return {
fillColor: 'rgba(255, 255, 255, 0)',
strokeColor: colors[i],
pointColor: colors[i],
pointStrokeColor: "#fff",
data: times
};
})
}, {
bezierCurve: false
});
goButton.disabled = false;
goButton.textContent = 'Run Benchmarks';
statusSpan.textContent = '';
}
function updateStatus(benchmark, mutationCount, count) {
statusSpan.textContent = 'Testing: ' +
benchmark.objectCount + ' objects, ' +
mutationCount + ' mutations ... ' +
count + ' runs';
}
var benchmarks = objectCounts.map(function(objectCount) {
return new benchmark(configSelect.value, objectCount);
});
Benchmark.all(benchmarks, mutationCounts, updateStatus)
.then(benchmarkComplete);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,357 @@
/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
(function(global) {
'use strict';
var createObject = ('__proto__' in {}) ?
function(obj) { return obj; } :
function(obj) {
var proto = obj.__proto__;
if (!proto)
return obj;
var newObject = Object.create(proto);
Object.getOwnPropertyNames(obj).forEach(function(name) {
Object.defineProperty(newObject, name,
Object.getOwnPropertyDescriptor(obj, name));
});
return newObject;
};
function ObservationBenchmark(objectCount) {
Benchmark.call(this);
this.objectCount = objectCount;
}
ObservationBenchmark.prototype = createObject({
__proto__: Benchmark.prototype,
setup: function() {
this.mutations = 0;
if (this.objects)
return;
this.objects = [];
this.observers = [];
this.objectIndex = 0;
while (this.objects.length < this.objectCount) {
var obj = this.newObject();
this.objects.push(obj);
var observer = this.newObserver(obj);
observer.open(this.observerCallback, this);
this.observers.push(observer);
}
},
test: function(mutationCount) {
while (mutationCount > 0) {
var obj = this.objects[this.objectIndex];
mutationCount -= this.mutateObject(obj);
this.mutations++;
this.objectIndex++;
if (this.objectIndex == this.objects.length) {
this.objectIndex = 0;
}
}
},
cleanup: function() {
if (this.mutations !== 0)
alert('Error: mutationCount == ' + this.mutationCount);
this.mutations = 0;
},
dispose: function() {
this.objects = null;
while (this.observers.length) {
this.observers.pop().close();
}
this.observers = null;
if (Observer._allObserversCount != 0) {
alert('Observers leaked');
}
},
observerCallback: function() {
this.mutations--;
}
});
function SetupObservationBenchmark(objectCount) {
Benchmark.call(this);
this.objectCount = objectCount;
}
SetupObservationBenchmark.prototype = createObject({
__proto__: Benchmark.prototype,
setup: function() {
this.mutations = 0;
this.objects = [];
this.observers = [];
while (this.objects.length < this.objectCount) {
var obj = this.newObject();
this.objects.push(obj);
}
},
test: function() {
for (var i = 0; i < this.objects.length; i++) {
var obj = this.objects[i];
var observer = this.newObserver(obj);
observer.open(this.observerCallback, this);
this.observers.push(observer);
}
},
cleanup: function() {
while (this.observers.length) {
this.observers.pop().close();
}
if (Observer._allObserversCount != 0) {
alert('Observers leaked');
}
this.objects = null;
this.observers = null;
},
dispose: function() {
}
});
function ObjectBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.properties = [];
for (var i = 0; i < ObjectBenchmark.propertyCount; i++) {
this.properties.push(String.fromCharCode(97 + i));
}
}
ObjectBenchmark.configs = [];
ObjectBenchmark.propertyCount = 15;
ObjectBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newObject: function() {
var obj = {};
for (var j = 0; j < ObjectBenchmark.propertyCount; j++)
obj[this.properties[j]] = j;
return obj;
},
newObserver: function(obj) {
return new ObjectObserver(obj);
},
mutateObject: function(obj) {
var size = Math.floor(ObjectBenchmark.propertyCount / 3);
for (var i = 0; i < size; i++) {
obj[this.properties[i]]++;
}
return size;
}
});
function SetupObjectBenchmark(config, objectCount) {
SetupObservationBenchmark.call(this, objectCount);
this.properties = [];
for (var i = 0; i < ObjectBenchmark.propertyCount; i++) {
this.properties.push(String.fromCharCode(97 + i));
}
}
SetupObjectBenchmark.configs = [];
SetupObjectBenchmark.propertyCount = 15;
SetupObjectBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newObject: function() {
var obj = {};
for (var j = 0; j < SetupObjectBenchmark.propertyCount; j++)
obj[this.properties[j]] = j;
return obj;
},
newObserver: function(obj) {
return new ObjectObserver(obj);
}
});
function ArrayBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
var tokens = config.split('/');
this.operation = tokens[0];
this.undo = tokens[1];
};
ArrayBenchmark.configs = ['splice', 'update', 'push/pop', 'shift/unshift'];
ArrayBenchmark.elementCount = 100;
ArrayBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newObject: function() {
var array = [];
for (var i = 0; i < ArrayBenchmark.elementCount; i++)
array.push(i);
return array;
},
newObserver: function(array) {
return new ArrayObserver(array);
},
mutateObject: function(array) {
switch (this.operation) {
case 'update':
var mutationsMade = 0;
var size = Math.floor(ArrayBenchmark.elementCount / 10);
for (var j = 0; j < size; j++) {
array[j*size] += 1;
mutationsMade++;
}
return mutationsMade;
case 'splice':
var size = Math.floor(ArrayBenchmark.elementCount / 5);
var removed = array.splice(size, size);
Array.prototype.splice.apply(array, [size*2, 0].concat(removed));
return size * 2;
default:
var val = array[this.undo]();
array[this.operation](val + 1);
return 2;
}
}
});
function SetupArrayBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
};
SetupArrayBenchmark.configs = [];
SetupArrayBenchmark.propertyCount = 15;
SetupArrayBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newObject: function() {
var array = [];
for (var i = 0; i < ArrayBenchmark.elementCount; i++)
array.push(i);
return array;
},
newObserver: function(array) {
return new ArrayObserver(array);
}
});
function PathBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.leaf = config === 'leaf';
this.path = Path.get('foo.bar.baz');
this.firstPathProp = Path.get(this.path[0]);
}
PathBenchmark.configs = ['leaf', 'root'];
PathBenchmark.prototype = createObject({
__proto__: ObservationBenchmark.prototype,
newPath: function(parts, value) {
var obj = {};
var ref = obj;
var prop;
for (var i = 0; i < parts.length - 1; i++) {
prop = parts[i];
ref[prop] = {};
ref = ref[prop];
}
prop = parts[parts.length - 1];
ref[prop] = value;
return obj;
},
newObject: function() {
return this.newPath(this.path, 1);
},
newObserver: function(obj) {
return new PathObserver(obj, this.path);
},
mutateObject: function(obj) {
var val = this.path.getValueFrom(obj);
if (this.leaf) {
this.path.setValueFrom(obj, val + 1);
} else {
this.firstPathProp.setValueFrom(obj, this.newPath(this.path.slice(1), val + 1));
}
return 1;
}
});
function SetupPathBenchmark(config, objectCount) {
ObservationBenchmark.call(this, objectCount);
this.path = Path.get('foo.bar.baz');
}
SetupPathBenchmark.configs = [];
SetupPathBenchmark.prototype = createObject({
__proto__: SetupObservationBenchmark.prototype,
newPath: function(parts, value) {
var obj = {};
var ref = obj;
var prop;
for (var i = 0; i < parts.length - 1; i++) {
prop = parts[i];
ref[prop] = {};
ref = ref[prop];
}
prop = parts[parts.length - 1];
ref[prop] = value;
return obj;
},
newObject: function() {
return this.newPath(this.path, 1);
},
newObserver: function(obj) {
return new PathObserver(obj, this.path);
}
});
global.ObjectBenchmark = ObjectBenchmark;
global.SetupObjectBenchmark = SetupObjectBenchmark;
global.ArrayBenchmark = ArrayBenchmark;
global.SetupArrayBenchmark = SetupArrayBenchmark;
global.PathBenchmark = PathBenchmark;
global.SetupPathBenchmark = SetupPathBenchmark;
})(this);