| <!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> |