processing-js
Version:
For the project website, visit http://processingjs.org
383 lines (333 loc) • 13.7 kB
HTML
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Processing.js Performance Tests</title>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
google.load('visualization', '1', {'packages':['corechart']});
</script>
<script src="../../processing.js"></script>
<script src="tests.js"></script>
<style>
.test { border: solid 1px; margin: 5px; }
.title { margin-left: 5px; }
</style>
</head>
<body>
<h1>Processing.js Performance Test Runner</h1>
<p>To start the tests click Start. Each test is run in order (downloaded from the server). Tests are run for a maximum number of frames (specified below), and the time recorded.</p>
<p>Reference tests can be run from <a href="/ref" target="_blank">here.</a>
<h3>Settings</h3>
<div>Run Tests: <select id="test-type" onchange="updateSelectedTests();">
<option value="2D,3D" selected="selected">2D and 3D</option>
<option value="2D">2D Only</option>
<option value="3D">3D Only</option>
<option value="Blend">Blend Only</option>
<option value="PImage">PImage Only</option>
<option value="PVector">PVector Only</option>
<option value="Crisp">Crisp</option>
<option value="Calibration">Calibration</option>
</select>
Iterations Per Test: <input type="text" size="4" id="iterations" onchange="updateIterations();">
<input onclick="runTests(selectedTests);" type="button" value="Start"></input><span id="testCount"></span></div>
<h3>Results [total time for <span id="curTest">0</span> tests: <span id="totalTime">0</span>ms] <button id="report" style="display:none" onclick="report();">Generate Report</button></h3>
<div id="status" style="margin-bottom: 10px; display: none;">Running... (this may take some time)</div>
<div id="results-chart"></div>
<div id="results" style="margin: 5px; padding-top: 10px;"></div>
<div id="total"></div>
<script>
var MAX_TEST_TIME = 5000; // ms of time to allow a test to run before halting and failing.
var selectedTests = [];
var finishedTests;
var failedTests = 0;
var totalTime = 0;
var total = document.getElementById('total');
total.innerHTML = '';
updateSelectedTests();
// Tolerance values and kernel for blur
var iterationCount = 1000;
document.getElementById('iterations').value = iterationCount;
function generateReport(tests) {
var report = {
testDate: Date.now(),
userAgent: window.navigator.userAgent,
data: []
};
for (var i=0; i < tests.length; i++) {
if (tests[i].completed) {
report.data.push(tests[i]);
}
}
return JSON.stringify(report);
}
function report() {
if (!finishedTests) {
alert("You must run the tests first.");
return;
}
// Using text/plain vs. application/json so it's easier to copy/paste
document.location.href = "data:text/plain," + generateReport(finishedTests);
}
/**
* Set up the test run filters
*/
function updateSelectedTests() {
var selectControl = document.getElementById('test-type');
var selectedTags = selectControl.value.split(',');
selectedTests = new Array();
for (var i = 0; i < tests.length; ++i) {
var found = false;
// checking if any selected tags present in test tags
for (var j = 0; j < selectedTags.length && !found; ++j) {
for (var q = 0; q < tests[i].tags.length && !found; ++q) {
if (tests[i].tags[q] == selectedTags[j]) found = true;
}
}
if (found) {
selectedTests.push(tests[i]);
}
}
var testCount = document.getElementById('testCount');
testCount.innerHTML = ' (' + selectedTests.length + ' tests)';
}
/**
* Change how many times each perf test runs before reporting
*/
function updateIterations() {
var newIterationCount = document.getElementById('iterations').value;
if (newIterationCount) {
iterationCount = parseInt(newIterationCount, 10);
}
}
/**
* get a file with cache breaking t=...
*/
function download(file) {
var req = new XMLHttpRequest();
req.open('GET', file + "?t=" + Date.now(), false);
if (req.overrideMimeType) {
req.overrideMimeType('text/plain');
}
req.send(null);
if (req.status != 200 && req.status !=0) {
return null;
} else {
return req.responseText;
}
}
/**
* get a test's source code
*/
function getTest(testName) {
var responseText = download(testName);
function is3D(script) {
// look for size(100,100,OPENGL) or size(100,100,P3D)
var match = script.match(/size\([\s]*[\d]+[\s]*\,[\s]*[\d]+[\s]*\,?([^\)]+)?\)/);
if (match && match[1]) {
return match[1] == "OPENGL" || match[1] == "P3D";
}
return false;
}
if (!responseText) {
return null;
}
// Split out the canvas info in the comment:
var test = {name: testName, code: responseText};
test.is3D = is3D(test.code);
return test;
}
/**
* Generate the performance chart after running all tests
*/
function drawResultsChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('string', 'Test');
dataTable.addColumn('number', 'Time per Frame (ms)');
var test, i;
for (i=0; i<tests.length; i++) {
test = tests[i];
dataTable.addRow([test.path,
test.time / (test.iterationOverride || iterationCount)]);
}
var chart = new google.visualization.BarChart(document.getElementById('results-chart'));
chart.draw(dataTable,
{ title: 'Performance Test Results',
width: 800,
height: 600,
legend: 'none',
vAxis: {title: 'Test', textPosition: 'none'},
hAxis: {title: 'Time per Frame (ms)'}
});
}
/**
* Run all performance tests
*/
function runTests(tests) {
var results = document.getElementById('results');
results.innerHTML = '';
var total = document.getElementById('total');
total.innerHTML = '';
var chart = document.getElementById('results-chart');
chart.innerHTML = '';
document.getElementById('report').style.display = "none";
finishedTests = null;
failedTests = 0;
totalTime = 0;
var buildCanvas = function(id, w, h) {
var c = document.createElement('canvas');
c.id = id;
c.width = w;
c.height = h;
c.className = "test";
return c;
};
var link = function(name) {
return '<a href="' + name + '">' + name + '</a>';
};
var titleText = function(testNumber, testTotal, time, testName, testIterations, failMessage) {
return "Test (" + testNumber + "/" + testTotal + ") " + link(testName) +
(failMessage ? " -- FAILED (" + failMessage + ")" : " -- Total Time for " + testIterations + " frames: <b>" + time + "ms</b>");
};
var tl = tests.length;
var lastTest = 0;
function nextTest(testNum) {
if (testNum < tl) {
window.setTimeout(function() { runOne(testNum); }, 50);
} else {
var passed = tl - failedTests;
var info = "Completed " + passed + " of " + tl + " tests (" + failedTests + " failed).";
document.getElementById('status').innerHTML = info;
total.innerHTML = info;
finishedTests = tests;
document.getElementById('status').style.display = "none";
document.getElementById('report').style.display = "inline";
// sort the tests into failed and passed
var sortedDivs = [];
while (results.hasChildNodes()) {
sortedDivs.push(results.firstChild);
results.removeChild(results.firstChild);
}
var failedDiv = document.createElement('div');
failedDiv.innerHTML = '<hr><h3>Failed ' + failedTests + ' of ' + (passed + failedTests) + '</h3>';
results.appendChild(failedDiv);
var passDiv = document.createElement('div');
passDiv.innerHTML = '<hr><h3>Passed ' + passed + ' of ' + (passed + failedTests) + '</h3>';
results.appendChild(passDiv);
for (var i = 0; i < sortedDivs.length; i++) {
if (sortedDivs[i].className === 'failed') {
failedDiv.appendChild(sortedDivs[i]);
} else {
passDiv.appendChild(sortedDivs[i]);
}
}
if (failedDiv.childNodes.length === 0) {
var temp = document.createElement('p');
temp.innerHTML = 'No failed tests';
failedDiv.appendChild(temp);
}
drawResultsChart();
}
}
function runOne(i) {
if (!tests[i]) {
alert("Error: no test found.");
return;
}
var test = getTest(tests[i].path);
var iterCount = tests[i].iterationOverride || iterationCount;
var result = document.createElement('div');
result.id = test.name;
var title = document.createElement('div');
title.className = "title";
result.appendChild(title);
results.appendChild(result);
if (test) {
var canvas = buildCanvas(test.name + '-canvas', test.width, test.height);
result.appendChild(canvas);
// draw the current version from code, timing it
var p;
try {
// Force the test to not loop--we'll do that.
var code = "noLoop();\n" + test.code;
p = new Processing(canvas, code);
function runBenchmark() {
try {
var startTime = Date.now(),
failed = false;
for (var iters = 0; iters < iterCount; iters++) {
if ( Date.now() - startTime > MAX_TEST_TIME ) {
// Exceeded allowable test run time, fail and bail
failed = true;
failedTests++;
break;
}
p.redraw();
}
var endTime = Date.now();
var diff = endTime - startTime;
totalTime += diff;
if (failed) {
result.className = "failed";
title.innerHTML = titleText(i+1, tl, "-", test.name, iterCount,
"Test exceeded maximum test time (" + MAX_TEST_TIME + "ms), halted.");
} else {
result.className = "passed";
title.innerHTML = titleText(i+1, tl, diff, test.name, iterCount);
}
document.getElementById('totalTime').innerHTML = totalTime;
document.getElementById('curTest').innerHTML = (i+1);
// Mark this test run a success with time
tests[i].completed = true;
tests[i].time = diff;
} catch (e) {
result.className = "failed";
title.innerHTML = titleText(i+1, tl, 0, test.name, iterCount, "Processing failed during execution: " + e.toString());
nextTest(i+1);
}
var is3D = p.use3DContext;
}
nextTest(i+1);
if (!p.draw) {
// preload present
var initInterval, attempts = 20;
initInterval = setInterval(function() {
if (p.draw) {
clearInterval(initInterval);
runBenchmark();
return;
}
if (--attempts <= 0) {
clearInterval(initInterval);
result.className = "failed";
title.innerHTML = titleText(i+1, tl, 0, test.name, iterCount, "Processing failed initialization");
nextTest(i+1);
return;
}
}, 100);
return;
}
runBenchmark();
p.exit();
p = null;
} catch (e) {
result.className = "failed";
title.innerHTML = titleText(i+1, tl, 0, test.name, iterCount, "Processing failed: " + e.toString());
nextTest(i+1);
}
}
};
window.setTimeout(function() { runOne(0); }, 25);
};
</script>
<!-- autorun -->
<script>
document.addEventListener("DOMContentLoaded", function() {
var loc = window.location.toString();
if(loc.indexOf("autorun=true") !== -1) {
runTests(selectedTests);
}
}, false);
</script>
</body>
</html>