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