1<!DOCTYPE HTML> 2<html> 3 <head> 4 <title>Performance Tests (2)</title> 5 <style> 6 body { font-family: Tahoma, Serif; font-size: 9pt; } 7 8 .left { text-align: left; } 9 .right { text-align: right; } 10 .center { text-align: center; } 11 12 table.resultTable 13 { 14 border: 1px solid black; 15 border-collapse: collapse; 16 empty-cells: show; 17 width: 100%; 18 } 19 table.resultTable td 20 { 21 padding: 2px 4px; 22 border: 1px solid black; 23 } 24 table.resultTable > thead > tr 25 { 26 font-weight: bold; 27 background: lightblue; 28 } 29 table.resultTable > tbody > tr:nth-child(odd) 30 { 31 background: white; 32 } 33 table.resultTable > tbody > tr:nth-child(even) 34 { 35 background: lightgray; 36 } 37 38 .hide { display: none; } 39 </style> 40 </head> 41 <body bgcolor="white"> 42 <h1>Performance Tests (2)</h1> 43 44 <form id="sForm" onsubmit="runTestSuite();return false"> 45 <table> 46 <tr> 47 <td colspan="2">Settings:</td> 48 </tr> 49 <tr> 50 <td class="right">Iterations:</td> 51 <td><input id="sIterations" type="text" value="1000" required pattern="[0-9]+" /></td> 52 </tr> 53 <tr> 54 <td class="right">Samples:</td> 55 <td><input id="sSamples" type="text" value="100" required pattern="[0-9]+" /></td> 56 </tr> 57 <tr> 58 <td class="right">Mode:</td> 59 <td><input id="sAsync" name="sMode" type="radio" value="async" checked>Asynchronous</input> 60 <input id="sSync" name="sMode" type="radio" value="sync">Synchronous</input> 61 </td> 62 </tr> 63 <tr> 64 <td colspan="2"><button type="submit" id="sRun" autofocus>Run!</button></td> 65 </tr> 66 </table> 67 </form> 68 69 70 <div><span id="statusBox"></span> <progress id="progressBox" value="0" style="display:none"></progress></div> 71 72 <div style="padding-top:10px; padding-bottom:10px"> 73 <table id="resultTable" class="resultTable"> 74 <thead> 75 <tr> 76 <td class="center" style="width:1%">Enabled</td> 77 <td class="center" style="width:10%">Name</td> 78 <td class="center" style="width:5%">Samples x Iterations</td> 79 <td class="center" style="width:5%">Min, ms</td> 80 <td class="center" style="width:5%">Avg, ms</td> 81 <td class="center" style="width:5%">Max, ms</td> 82 <td class="center" style="width:5%">Average calls/sec</td> 83 <td class="center" style="width:5%">Measuring Inacurracy</td> 84 <td class="center hide" style="width:5%">Memory, MB</td> 85 <td class="center hide" style="width:5%">Memory delta, MB</td> 86 <td class="center" style="width:55%">Description</td> 87 </tr> 88 </thead> 89 <tbody> 90 <!-- result rows here --> 91 </tbody> 92 </table> 93 </div> 94 95<script type="text/javascript"> 96(function () { 97 function getPrivateWorkingSet() { 98 return 0; // TODO: window.PerfTestGetPrivateWorkingSet(); 99 } 100 101 var disableWarmUp = true; 102 103 var asyncExecution = true; 104 var testIterations = 1000; 105 var totalSamples = 100; 106 var sampleDelay = 0; 107 108 var collectSamples = false; 109 110 var tests = []; 111 var testIndex = -1; 112 113 function execTestFunc(test) { 114 try { 115 var begin = new Date(); 116 test.func(test.totalIterations); 117 var end = new Date(); 118 return (end - begin); 119 } catch (e) { 120 test.error = e.toString(); 121 return 0; 122 } 123 } 124 125 function execTest(test) { 126 if (disableWarmUp) { test.warmedUp = true; } 127 128 function nextStep() { 129 if (asyncExecution) { 130 setTimeout(function () { execTest(test); }, sampleDelay); 131 } else { 132 execTest(test); 133 } 134 } 135 136 function nextTest() { 137 updateStatus(test); 138 appendResult(test); 139 140 return execNextTest(); 141 } 142 143 updateStatus(test); 144 if (!test.warmedUp) { 145 execTestFunc(test); 146 if (!test.error) { 147 test.warmedUp = true; 148 test.beginMemory = getPrivateWorkingSet(); 149 return nextStep(); 150 } else { 151 return nextTest(); 152 } 153 } 154 155 if (test.sample >= test.totalSamples) { 156 test.avg = test.total / test.totalSamples; 157 test.endMemory = getPrivateWorkingSet(); 158 return nextTest(); 159 } 160 161 if (test.skipped) return nextTest(); 162 163 var elapsed = execTestFunc(test); 164 if (!test.error) { 165 test.total += elapsed; 166 if (!test.min) test.min = elapsed; 167 else if (test.min > elapsed) test.min = elapsed; 168 if (!test.max) test.max = elapsed; 169 else if (test.max < elapsed) test.max = elapsed; 170 if (collectSamples) { 171 test.results.push(elapsed); 172 } 173 test.sample++; 174 return nextStep(); 175 } else { 176 return nextTest(); 177 } 178 } 179 180 function updateStatus(test) { 181 var statusBox = document.getElementById("statusBox"); 182 var progressBox = document.getElementById("progressBox"); 183 184 if (test.skipped || test.error || test.sample >= test.totalSamples) { 185 statusBox.innerText = ""; 186 progressBox.style.display = "none"; 187 } else { 188 statusBox.innerText = (testIndex + 1) + "/" + tests.length + ": " + test.name + " (" + test.sample + "/" + test.totalSamples + ")"; 189 progressBox.value = (test.sample / test.totalSamples); 190 progressBox.style.display = "inline"; 191 } 192 } 193 194 function appendResult(test) { 195 if (test.name == "warmup") return; 196 197 var id = "testResultRow_" + test.index; 198 199 var nearBound = (test.max - test.avg) < (test.avg - test.min) ? test.max : test.min; 200 var memoryDelta = test.endMemory - test.beginMemory; 201 if (memoryDelta < 0) memoryDelta = "-" + Math.abs(memoryDelta).toFixed(2); 202 else memoryDelta = "+" + Math.abs(memoryDelta).toFixed(2); 203 204 var markup = ["<tr id='" + id + "'>", 205 "<td class='left'><input type='checkbox' id='test_enabled_", test.index ,"' ", (!test.skipped ? "checked" : "") ," /></td>", 206 "<td class='left'>", test.name, "</td>", 207 "<td class='right'>", test.totalSamples, "x", test.totalIterations, "</td>", 208 "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.min.toFixed(2), "</td>", 209 "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.avg.toFixed(2), "</td>", 210 "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.max.toFixed(2), "</td>", 211 "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : (test.totalIterations * 1000 / test.avg).toFixed(2), "</td>", 212 "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : ("± " + (Math.abs(test.avg - nearBound) / (test.avg) * (100)).toFixed(2) + "%"), "</td>", 213 "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : test.endMemory.toFixed(2), "</td>", 214 "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : memoryDelta, "</td>", 215 "<td class='left'>", test.description, test.error ? (test.description ? "<br/>" : "") + "<span style='color:red'>" + test.error + "</span>" : "", "</td>", 216 "</tr>" 217 ].join(""); 218 // test.results.join(", "), "<br/>", 219 220 var row = document.getElementById(id); 221 if (row) { 222 row.outerHTML = markup; 223 } else { 224 var tbody = document.getElementById("resultTable").tBodies[0]; 225 tbody.insertAdjacentHTML("beforeEnd", markup); 226 } 227 } 228 229 function prepareQueuedTests() { 230 testIndex = -1; 231 for (var i = 0; i < tests.length; i++) { 232 var test = tests[i]; 233 test.index = i; 234 test.prepared = false; 235 test.warmedUp = false; 236 test.sample = 0; 237 test.total = 0; 238 test.results = []; 239 test.error = false; 240 test.min = null; 241 test.avg = null; 242 test.max = null; 243 test.beginMemory = null; 244 test.endMemory = null; 245 test.totalIterations = parseInt(testIterations / test.complex); 246 test.totalSamples = parseInt(totalSamples / test.complex); 247 248 var skipElement = document.getElementById('test_enabled_' + test.index); 249 test.skipped = skipElement ? !skipElement.checked : (test.skipped || false); 250 251 if (test.totalIterations <= 0) test.totalIterations = 1; 252 if (test.totalSamples <= 0) test.totalSamples = 1; 253 254 appendResult(test); 255 test.prepared = true; 256 } 257 } 258 259 function queueTest(func, name, description) { 260 var test; 261 if (typeof func === "function") { 262 test = { 263 name: name, 264 func: func, 265 description: description 266 }; 267 } else { 268 test = func; 269 } 270 test.warmedUp = false; 271 test.complex = test.complex || 1; 272 tests.push(test); 273 } 274 275 function execNextTest() { 276 testIndex++; 277 if (tests.length <= testIndex) { 278 return testSuiteFinished(); 279 } else { 280 return execTest(tests[testIndex]); 281 } 282 } 283 284 function execQueuedTests() { 285 prepareQueuedTests(); 286 execNextTest(); 287 } 288 289 function setSettingsState(disabled) { 290 document.getElementById('sIterations').disabled = disabled; 291 document.getElementById('sSamples').disabled = disabled; 292 document.getElementById('sAsync').disabled = disabled; 293 document.getElementById('sSync').disabled = disabled; 294 document.getElementById('sRun').disabled = disabled; 295 } 296 297 function testSuiteFinished() { 298 setSettingsState(false); 299 } 300 301 window.runTestSuite = function () { 302 setSettingsState(true); 303 304 testIterations = parseInt(document.getElementById('sIterations').value); 305 totalSamples = parseInt(document.getElementById('sSamples').value); 306 asyncExecution = document.getElementById('sAsync').checked; 307 308 setTimeout(execQueuedTests, 0); 309 } 310 311 setTimeout(prepareQueuedTests, 0); 312 313 // Test queue. 314 queueTest({ 315 name: "PerfTestReturnValue Default", 316 func: function (count) { 317 for (var i = 0; i < count; i++) { 318 window.PerfTestReturnValue(); 319 } 320 }, 321 description: "No arguments, returns int32 value.", 322 skipped: true, 323 }); 324 325 queueTest({ 326 name: "PerfTestReturnValue (0, Undefined)", 327 func: function (count) { 328 for (var i = 0; i < count; i++) { 329 window.PerfTestReturnValue(0); 330 } 331 }, 332 description: "Int argument, returns undefined value." 333 }); 334 335 queueTest({ 336 name: "PerfTestReturnValue (1, Null)", 337 func: function (count) { 338 for (var i = 0; i < count; i++) { 339 window.PerfTestReturnValue(1); 340 } 341 }, 342 description: "Int argument, returns null value." 343 }); 344 345 queueTest({ 346 name: "PerfTestReturnValue (2, Bool)", 347 func: function (count) { 348 for (var i = 0; i < count; i++) { 349 window.PerfTestReturnValue(2); 350 } 351 }, 352 description: "Int argument, returns bool value." 353 }); 354 355 queueTest({ 356 name: "PerfTestReturnValue (3, Int)", 357 func: function (count) { 358 for (var i = 0; i < count; i++) { 359 window.PerfTestReturnValue(3); 360 } 361 }, 362 description: "Int argument, returns int value." 363 }); 364 365 queueTest({ 366 name: "PerfTestReturnValue (4, UInt)", 367 func: function (count) { 368 for (var i = 0; i < count; i++) { 369 window.PerfTestReturnValue(4); 370 } 371 }, 372 description: "Int argument, returns uint value." 373 }); 374 375 queueTest({ 376 name: "PerfTestReturnValue (5, Double)", 377 func: function (count) { 378 for (var i = 0; i < count; i++) { 379 window.PerfTestReturnValue(5); 380 } 381 }, 382 description: "Int argument, returns double value." 383 }); 384 385 queueTest({ 386 name: "PerfTestReturnValue (6, Date)", 387 func: function (count) { 388 for (var i = 0; i < count; i++) { 389 window.PerfTestReturnValue(6); 390 } 391 }, 392 description: "Int argument, returns date value.", 393 skipped: true, 394 }); 395 396 queueTest({ 397 name: "PerfTestReturnValue (7, String)", 398 func: function (count) { 399 for (var i = 0; i < count; i++) { 400 window.PerfTestReturnValue(7); 401 } 402 }, 403 description: "Int argument, returns string value." 404 }); 405 406 queueTest({ 407 name: "PerfTestReturnValue (8, Object)", 408 func: function (count) { 409 for (var i = 0; i < count; i++) { 410 window.PerfTestReturnValue(8); 411 } 412 }, 413 description: "Int argument, returns object value." 414 }); 415 416 queueTest({ 417 name: "PerfTestReturnValue (9, Array)", 418 func: function (count) { 419 for (var i = 0; i < count; i++) { 420 window.PerfTestReturnValue(9); 421 } 422 }, 423 description: "Int argument, returns array value." 424 }); 425 426 queueTest({ 427 name: "PerfTestReturnValue (10, Function)", 428 func: function (count) { 429 for (var i = 0; i < count; i++) { 430 window.PerfTestReturnValue(10); 431 } 432 }, 433 description: "Int argument, returns function value.", 434 skipped: true, 435 }); 436 // add more tests to queueTest 437 438})(); 439</script> 440 441 </body> 442</html> 443