--- /dev/null
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Performance Tests (2)</title>
+ <style>
+ body { font-family: Tahoma, Serif; font-size: 9pt; }
+
+ .left { text-align: left; }
+ .right { text-align: right; }
+ .center { text-align: center; }
+
+ table.resultTable
+ {
+ border: 1px solid black;
+ border-collapse: collapse;
+ empty-cells: show;
+ width: 100%;
+ }
+ table.resultTable td
+ {
+ padding: 2px 4px;
+ border: 1px solid black;
+ }
+ table.resultTable > thead > tr
+ {
+ font-weight: bold;
+ background: lightblue;
+ }
+ table.resultTable > tbody > tr:nth-child(odd)
+ {
+ background: white;
+ }
+ table.resultTable > tbody > tr:nth-child(even)
+ {
+ background: lightgray;
+ }
+
+ .hide { display: none; }
+ </style>
+ </head>
+ <body bgcolor="white">
+ <h1>Performance Tests (2)</h1>
+
+ <form id="sForm" onsubmit="runTestSuite();return false">
+ <table>
+ <tr>
+ <td colspan="2">Settings:</td>
+ </tr>
+ <tr>
+ <td class="right">Iterations:</td>
+ <td><input id="sIterations" type="text" value="1000" required pattern="[0-9]+" /></td>
+ </tr>
+ <tr>
+ <td class="right">Samples:</td>
+ <td><input id="sSamples" type="text" value="100" required pattern="[0-9]+" /></td>
+ </tr>
+ <tr>
+ <td class="right">Mode:</td>
+ <td><input id="sAsync" name="sMode" type="radio" value="async" checked>Asynchronous</input>
+ <input id="sSync" name="sMode" type="radio" value="sync">Synchronous</input>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"><button type="submit" id="sRun" autofocus>Run!</button></td>
+ </tr>
+ </table>
+ </form>
+
+
+ <div><span id="statusBox"></span> <progress id="progressBox" value="0" style="display:none"></progress></div>
+
+ <div style="padding-top:10px; padding-bottom:10px">
+ <table id="resultTable" class="resultTable">
+ <thead>
+ <tr>
+ <td class="center" style="width:1%">Enabled</td>
+ <td class="center" style="width:10%">Name</td>
+ <td class="center" style="width:5%">Samples x Iterations</td>
+ <td class="center" style="width:5%">Min, ms</td>
+ <td class="center" style="width:5%">Avg, ms</td>
+ <td class="center" style="width:5%">Max, ms</td>
+ <td class="center" style="width:5%">Average calls/sec</td>
+ <td class="center" style="width:5%">Measuring Inacurracy</td>
+ <td class="center hide" style="width:5%">Memory, MB</td>
+ <td class="center hide" style="width:5%">Memory delta, MB</td>
+ <td class="center" style="width:55%">Description</td>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- result rows here -->
+ </tbody>
+ </table>
+ </div>
+
+<script type="text/javascript">
+(function () {
+ function getPrivateWorkingSet() {
+ return 0; // TODO: window.PerfTestGetPrivateWorkingSet();
+ }
+
+ var disableWarmUp = true;
+
+ var asyncExecution = true;
+ var testIterations = 1000;
+ var totalSamples = 100;
+ var sampleDelay = 0;
+
+ var collectSamples = false;
+
+ var tests = [];
+ var testIndex = -1;
+
+ function execTestFunc(test) {
+ try {
+ var begin = new Date();
+ test.func(test.totalIterations);
+ var end = new Date();
+ return (end - begin);
+ } catch (e) {
+ test.error = e.toString();
+ return 0;
+ }
+ }
+
+ function execTest(test) {
+ if (disableWarmUp) { test.warmedUp = true; }
+
+ function nextStep() {
+ if (asyncExecution) {
+ setTimeout(function () { execTest(test); }, sampleDelay);
+ } else {
+ execTest(test);
+ }
+ }
+
+ function nextTest() {
+ updateStatus(test);
+ appendResult(test);
+
+ return execNextTest();
+ }
+
+ updateStatus(test);
+ if (!test.warmedUp) {
+ execTestFunc(test);
+ if (!test.error) {
+ test.warmedUp = true;
+ test.beginMemory = getPrivateWorkingSet();
+ return nextStep();
+ } else {
+ return nextTest();
+ }
+ }
+
+ if (test.sample >= test.totalSamples) {
+ test.avg = test.total / test.totalSamples;
+ test.endMemory = getPrivateWorkingSet();
+ return nextTest();
+ }
+
+ if (test.skipped) return nextTest();
+
+ var elapsed = execTestFunc(test);
+ if (!test.error) {
+ test.total += elapsed;
+ if (!test.min) test.min = elapsed;
+ else if (test.min > elapsed) test.min = elapsed;
+ if (!test.max) test.max = elapsed;
+ else if (test.max < elapsed) test.max = elapsed;
+ if (collectSamples) {
+ test.results.push(elapsed);
+ }
+ test.sample++;
+ return nextStep();
+ } else {
+ return nextTest();
+ }
+ }
+
+ function updateStatus(test) {
+ var statusBox = document.getElementById("statusBox");
+ var progressBox = document.getElementById("progressBox");
+
+ if (test.skipped || test.error || test.sample >= test.totalSamples) {
+ statusBox.innerText = "";
+ progressBox.style.display = "none";
+ } else {
+ statusBox.innerText = (testIndex + 1) + "/" + tests.length + ": " + test.name + " (" + test.sample + "/" + test.totalSamples + ")";
+ progressBox.value = (test.sample / test.totalSamples);
+ progressBox.style.display = "inline";
+ }
+ }
+
+ function appendResult(test) {
+ if (test.name == "warmup") return;
+
+ var id = "testResultRow_" + test.index;
+
+ var nearBound = (test.max - test.avg) < (test.avg - test.min) ? test.max : test.min;
+ var memoryDelta = test.endMemory - test.beginMemory;
+ if (memoryDelta < 0) memoryDelta = "-" + Math.abs(memoryDelta).toFixed(2);
+ else memoryDelta = "+" + Math.abs(memoryDelta).toFixed(2);
+
+ var markup = ["<tr id='" + id + "'>",
+ "<td class='left'><input type='checkbox' id='test_enabled_", test.index ,"' ", (!test.skipped ? "checked" : "") ," /></td>",
+ "<td class='left'>", test.name, "</td>",
+ "<td class='right'>", test.totalSamples, "x", test.totalIterations, "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.min.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.avg.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.max.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : (test.totalIterations * 1000 / test.avg).toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : ("± " + (Math.abs(test.avg - nearBound) / (test.avg) * (100)).toFixed(2) + "%"), "</td>",
+ "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : test.endMemory.toFixed(2), "</td>",
+ "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : memoryDelta, "</td>",
+ "<td class='left'>", test.description, test.error ? (test.description ? "<br/>" : "") + "<span style='color:red'>" + test.error + "</span>" : "", "</td>",
+ "</tr>"
+ ].join("");
+ // test.results.join(", "), "<br/>",
+
+ var row = document.getElementById(id);
+ if (row) {
+ row.outerHTML = markup;
+ } else {
+ var tbody = document.getElementById("resultTable").tBodies[0];
+ tbody.insertAdjacentHTML("beforeEnd", markup);
+ }
+ }
+
+ function prepareQueuedTests() {
+ testIndex = -1;
+ for (var i = 0; i < tests.length; i++) {
+ var test = tests[i];
+ test.index = i;
+ test.prepared = false;
+ test.warmedUp = false;
+ test.sample = 0;
+ test.total = 0;
+ test.results = [];
+ test.error = false;
+ test.min = null;
+ test.avg = null;
+ test.max = null;
+ test.beginMemory = null;
+ test.endMemory = null;
+ test.totalIterations = parseInt(testIterations / test.complex);
+ test.totalSamples = parseInt(totalSamples / test.complex);
+
+ var skipElement = document.getElementById('test_enabled_' + test.index);
+ test.skipped = skipElement ? !skipElement.checked : (test.skipped || false);
+
+ if (test.totalIterations <= 0) test.totalIterations = 1;
+ if (test.totalSamples <= 0) test.totalSamples = 1;
+
+ appendResult(test);
+ test.prepared = true;
+ }
+ }
+
+ function queueTest(func, name, description) {
+ var test;
+ if (typeof func === "function") {
+ test = {
+ name: name,
+ func: func,
+ description: description
+ };
+ } else {
+ test = func;
+ }
+ test.warmedUp = false;
+ test.complex = test.complex || 1;
+ tests.push(test);
+ }
+
+ function execNextTest() {
+ testIndex++;
+ if (tests.length <= testIndex) {
+ return testSuiteFinished();
+ } else {
+ return execTest(tests[testIndex]);
+ }
+ }
+
+ function execQueuedTests() {
+ prepareQueuedTests();
+ execNextTest();
+ }
+
+ function setSettingsState(disabled) {
+ document.getElementById('sIterations').disabled = disabled;
+ document.getElementById('sSamples').disabled = disabled;
+ document.getElementById('sAsync').disabled = disabled;
+ document.getElementById('sSync').disabled = disabled;
+ document.getElementById('sRun').disabled = disabled;
+ }
+
+ function testSuiteFinished() {
+ setSettingsState(false);
+ }
+
+ window.runTestSuite = function () {
+ setSettingsState(true);
+
+ testIterations = parseInt(document.getElementById('sIterations').value);
+ totalSamples = parseInt(document.getElementById('sSamples').value);
+ asyncExecution = document.getElementById('sAsync').checked;
+
+ setTimeout(execQueuedTests, 0);
+ }
+
+ setTimeout(prepareQueuedTests, 0);
+
+ // Test queue.
+ queueTest({
+ name: "PerfTestReturnValue Default",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue();
+ }
+ },
+ description: "No arguments, returns int32 value.",
+ skipped: true,
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (0, Undefined)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(0);
+ }
+ },
+ description: "Int argument, returns undefined value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (1, Null)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(1);
+ }
+ },
+ description: "Int argument, returns null value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (2, Bool)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(2);
+ }
+ },
+ description: "Int argument, returns bool value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (3, Int)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(3);
+ }
+ },
+ description: "Int argument, returns int value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (4, UInt)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(4);
+ }
+ },
+ description: "Int argument, returns uint value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (5, Double)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(5);
+ }
+ },
+ description: "Int argument, returns double value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (6, Date)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(6);
+ }
+ },
+ description: "Int argument, returns date value.",
+ skipped: true,
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (7, String)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(7);
+ }
+ },
+ description: "Int argument, returns string value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (8, Object)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(8);
+ }
+ },
+ description: "Int argument, returns object value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (9, Array)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(9);
+ }
+ },
+ description: "Int argument, returns array value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (10, Function)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(10);
+ }
+ },
+ description: "Int argument, returns function value.",
+ skipped: true,
+ });
+ // add more tests to queueTest
+
+})();
+</script>
+
+ </body>
+</html>