1*44a87f08Sstephan<!doctype html> 2*44a87f08Sstephan<html lang="en-us"> 3*44a87f08Sstephan <head> 4*44a87f08Sstephan <meta charset="utf-8"> 5*44a87f08Sstephan <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 6*44a87f08Sstephan <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> 7*44a87f08Sstephan <link rel="stylesheet" href="common/emscripten.css"/> 8*44a87f08Sstephan <link rel="stylesheet" href="common/testing.css"/> 9*44a87f08Sstephan <title>speedtest1.wasm Worker</title> 10*44a87f08Sstephan </head> 11*44a87f08Sstephan <body> 12*44a87f08Sstephan <header id='titlebar'>speedtest1.wasm Worker</header> 13*44a87f08Sstephan <div>See also: <a href='speedtest1.html'>A main-thread variant of this page.</a></div> 14*44a87f08Sstephan <!-- emscripten bits --> 15*44a87f08Sstephan <figure id="module-spinner"> 16*44a87f08Sstephan <div class="spinner"></div> 17*44a87f08Sstephan <div class='center'><strong>Initializing app...</strong></div> 18*44a87f08Sstephan <div class='center'> 19*44a87f08Sstephan On a slow internet connection this may take a moment. If this 20*44a87f08Sstephan message displays for "a long time", intialization may have 21*44a87f08Sstephan failed and the JavaScript console may contain clues as to why. 22*44a87f08Sstephan </div> 23*44a87f08Sstephan </figure> 24*44a87f08Sstephan <div class="emscripten" id="module-status">Downloading...</div> 25*44a87f08Sstephan <div class="emscripten"> 26*44a87f08Sstephan <progress value="0" max="100" id="module-progress" hidden='1'></progress> 27*44a87f08Sstephan </div><!-- /emscripten bits --> 28*44a87f08Sstephan <fieldset id='ui-controls' class='hidden'> 29*44a87f08Sstephan <legend>Options</legend> 30*44a87f08Sstephan <div id='toolbar'> 31*44a87f08Sstephan <div id='toolbar-select'> 32*44a87f08Sstephan <select id='select-flags' size='10' multiple></select> 33*44a87f08Sstephan <div>TODO? Options which require values are not represented here.</div> 34*44a87f08Sstephan </div> 35*44a87f08Sstephan <div class='toolbar-inner-vertical' id='toolbar-selected-flags'> 36*44a87f08Sstephan <button id='btn-reset-flags'>Reset Flags</button> 37*44a87f08Sstephan <button id='btn-output-clear'>Clear output</button> 38*44a87f08Sstephan <button id='btn-run'>Run</button> 39*44a87f08Sstephan </div> 40*44a87f08Sstephan <div class='toolbar-inner-vertical' id='toolbar-runner-controls'> 41*44a87f08Sstephan <button id='btn-reset-flags'>Reset Flags</button> 42*44a87f08Sstephan <button id='btn-output-clear'>Clear output</button> 43*44a87f08Sstephan <button id='btn-run'>Run</button> 44*44a87f08Sstephan </div> 45*44a87f08Sstephan </div> 46*44a87f08Sstephan </fieldset> 47*44a87f08Sstephan <div> 48*44a87f08Sstephan <span class='input-wrapper'> 49*44a87f08Sstephan <input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input> 50*44a87f08Sstephan <label for='cb-reverse-log-order' id='lbl-reverse-log-order'>Reverse log order</label> 51*44a87f08Sstephan </span> 52*44a87f08Sstephan </div> 53*44a87f08Sstephan <div id='test-output'></div> 54*44a87f08Sstephan <style> 55*44a87f08Sstephan #test-output { 56*44a87f08Sstephan white-space: break-spaces; 57*44a87f08Sstephan overflow: auto; 58*44a87f08Sstephan } 59*44a87f08Sstephan #toolbar { 60*44a87f08Sstephan display: flex; 61*44a87f08Sstephan flex-direction: row; 62*44a87f08Sstephan flex-wrap: wrap; 63*44a87f08Sstephan } 64*44a87f08Sstephan #toolbar > * { 65*44a87f08Sstephan margin: 0 0.5em; 66*44a87f08Sstephan } 67*44a87f08Sstephan .toolbar-inner-vertical { 68*44a87f08Sstephan display: flex; 69*44a87f08Sstephan flex-direction: column; 70*44a87f08Sstephan justify-content: space-between; 71*44a87f08Sstephan } 72*44a87f08Sstephan #toolbar-select { 73*44a87f08Sstephan display: flex; 74*44a87f08Sstephan flex-direction: column; 75*44a87f08Sstephan } 76*44a87f08Sstephan .toolbar-inner-vertical > *, #toolbar-select > * { 77*44a87f08Sstephan margin: 0.2em 0; 78*44a87f08Sstephan } 79*44a87f08Sstephan #select-flags > option { 80*44a87f08Sstephan white-space: pre; 81*44a87f08Sstephan font-family: monospace; 82*44a87f08Sstephan } 83*44a87f08Sstephan fieldset { 84*44a87f08Sstephan border-radius: 0.5em; 85*44a87f08Sstephan } 86*44a87f08Sstephan #toolbar-runner-controls { flex-grow: 1 } 87*44a87f08Sstephan #toolbar-runner-controls > * { flex: 1 0 auto } 88*44a87f08Sstephan #toolbar-selected-flags::before { 89*44a87f08Sstephan font-family: initial; 90*44a87f08Sstephan content:"Selected flags: "; 91*44a87f08Sstephan } 92*44a87f08Sstephan #toolbar-selected-flags { 93*44a87f08Sstephan font-family: monospace; 94*44a87f08Sstephan justify-content: flex-start; 95*44a87f08Sstephan } 96*44a87f08Sstephan </style> 97*44a87f08Sstephan <script>(function(){ 98*44a87f08Sstephan 'use strict'; 99*44a87f08Sstephan const E = (sel)=>document.querySelector(sel); 100*44a87f08Sstephan const eOut = E('#test-output'); 101*44a87f08Sstephan const log2 = function(cssClass,...args){ 102*44a87f08Sstephan let ln; 103*44a87f08Sstephan if(1 || cssClass){ 104*44a87f08Sstephan ln = document.createElement('div'); 105*44a87f08Sstephan if(cssClass) ln.classList.add(cssClass); 106*44a87f08Sstephan ln.append(document.createTextNode(args.join(' '))); 107*44a87f08Sstephan }else{ 108*44a87f08Sstephan // This doesn't work with the "reverse order" option! 109*44a87f08Sstephan ln = document.createTextNode(args.join(' ')+'\n'); 110*44a87f08Sstephan } 111*44a87f08Sstephan eOut.append(ln); 112*44a87f08Sstephan }; 113*44a87f08Sstephan const log = (...args)=>{ 114*44a87f08Sstephan //console.log(...args); 115*44a87f08Sstephan log2('', ...args); 116*44a87f08Sstephan }; 117*44a87f08Sstephan const logErr = function(...args){ 118*44a87f08Sstephan //console.error(...args); 119*44a87f08Sstephan log2('error', ...args); 120*44a87f08Sstephan }; 121*44a87f08Sstephan const logWarn = function(...args){ 122*44a87f08Sstephan //console.warn(...args); 123*44a87f08Sstephan log2('warning', ...args); 124*44a87f08Sstephan }; 125*44a87f08Sstephan 126*44a87f08Sstephan const spacePad = function(str,len=18){ 127*44a87f08Sstephan if(str.length===len) return str; 128*44a87f08Sstephan else if(str.length>len) return str.substr(0,len); 129*44a87f08Sstephan const a = []; a.length = len - str.length; 130*44a87f08Sstephan return str+a.join(' '); 131*44a87f08Sstephan }; 132*44a87f08Sstephan // OPTION elements seem to ignore white-space:pre, so do this the hard way... 133*44a87f08Sstephan const nbspPad = function(str,len=18){ 134*44a87f08Sstephan if(str.length===len) return str; 135*44a87f08Sstephan else if(str.length>len) return str.substr(0,len); 136*44a87f08Sstephan const a = []; a.length = len - str.length; 137*44a87f08Sstephan return str+a.join(' '); 138*44a87f08Sstephan }; 139*44a87f08Sstephan 140*44a87f08Sstephan const W = new Worker("speedtest1-worker.js"); 141*44a87f08Sstephan const mPost = function(msgType,payload){ 142*44a87f08Sstephan W.postMessage({type: msgType, data: payload}); 143*44a87f08Sstephan }; 144*44a87f08Sstephan 145*44a87f08Sstephan const eFlags = E('#select-flags'); 146*44a87f08Sstephan const eSelectedFlags = E('#toolbar-selected-flags'); 147*44a87f08Sstephan 148*44a87f08Sstephan const getSelectedFlags = ()=>Array.prototype.map.call(eFlags.selectedOptions, (v)=>v.value); 149*44a87f08Sstephan const updateSelectedFlags = function(){ 150*44a87f08Sstephan eSelectedFlags.innerText = ''; 151*44a87f08Sstephan getSelectedFlags().forEach(function(f){ 152*44a87f08Sstephan const e = document.createElement('span'); 153*44a87f08Sstephan e.innerText = f; 154*44a87f08Sstephan eSelectedFlags.appendChild(e); 155*44a87f08Sstephan }); 156*44a87f08Sstephan }; 157*44a87f08Sstephan eFlags.addEventListener('change', updateSelectedFlags ); 158*44a87f08Sstephan { 159*44a87f08Sstephan const flags = Object.create(null); 160*44a87f08Sstephan /* TODO? Flags which require values need custom UI 161*44a87f08Sstephan controls and some of them make little sense here 162*44a87f08Sstephan (e.g. --script FILE). */ 163*44a87f08Sstephan flags["autovacuum"] = "Enable AUTOVACUUM mode"; 164*44a87f08Sstephan //flags["cachesize"] = "N Set the cache size to N"; 165*44a87f08Sstephan flags["checkpoint"] = "Run PRAGMA wal_checkpoint after each test case"; 166*44a87f08Sstephan flags["exclusive"] = "Enable locking_mode=EXCLUSIVE"; 167*44a87f08Sstephan flags["explain"] = "Like --sqlonly but with added EXPLAIN keywords"; 168*44a87f08Sstephan //flags["heap"] = "SZ MIN Memory allocator uses SZ bytes & min allocation MIN"; 169*44a87f08Sstephan flags["incrvacuum"] = "Enable incremenatal vacuum mode"; 170*44a87f08Sstephan //flags["journal"] = "M Set the journal_mode to M"; 171*44a87f08Sstephan //flags["key"] = "KEY Set the encryption key to KEY"; 172*44a87f08Sstephan //flags["lookaside"] = "N SZ Configure lookaside for N slots of SZ bytes each"; 173*44a87f08Sstephan flags["memdb"] = "Use an in-memory database"; 174*44a87f08Sstephan //flags["mmap"] = "SZ MMAP the first SZ bytes of the database file"; 175*44a87f08Sstephan flags["multithread"] = "Set multithreaded mode"; 176*44a87f08Sstephan flags["nomemstat"] = "Disable memory statistics"; 177*44a87f08Sstephan flags["nosync"] = "Set PRAGMA synchronous=OFF"; 178*44a87f08Sstephan flags["notnull"] = "Add NOT NULL constraints to table columns"; 179*44a87f08Sstephan //flags["output"] = "FILE Store SQL output in FILE"; 180*44a87f08Sstephan //flags["pagesize"] = "N Set the page size to N"; 181*44a87f08Sstephan //flags["pcache"] = "N SZ Configure N pages of pagecache each of size SZ bytes"; 182*44a87f08Sstephan //flags["primarykey"] = "Use PRIMARY KEY instead of UNIQUE where appropriate"; 183*44a87f08Sstephan //flags["repeat"] = "N Repeat each SELECT N times (default: 1)"; 184*44a87f08Sstephan flags["reprepare"] = "Reprepare each statement upon every invocation"; 185*44a87f08Sstephan //flags["reserve"] = "N Reserve N bytes on each database page"; 186*44a87f08Sstephan //flags["script"] = "FILE Write an SQL script for the test into FILE"; 187*44a87f08Sstephan flags["serialized"] = "Set serialized threading mode"; 188*44a87f08Sstephan flags["singlethread"] = "Set single-threaded mode - disables all mutexing"; 189*44a87f08Sstephan flags["sqlonly"] = "No-op. Only show the SQL that would have been run."; 190*44a87f08Sstephan flags["shrink"] = "memory Invoke sqlite3_db_release_memory() frequently."; 191*44a87f08Sstephan //flags["size"] = "N Relative test size. Default=100"; 192*44a87f08Sstephan flags["strict"] = "Use STRICT table where appropriate"; 193*44a87f08Sstephan flags["stats"] = "Show statistics at the end"; 194*44a87f08Sstephan //flags["temp"] = "N N from 0 to 9. 0: no temp table. 9: all temp tables"; 195*44a87f08Sstephan //flags["testset"] = "T Run test-set T (main, cte, rtree, orm, fp, debug)"; 196*44a87f08Sstephan flags["trace"] = "Turn on SQL tracing"; 197*44a87f08Sstephan //flags["threads"] = "N Use up to N threads for sorting"; 198*44a87f08Sstephan /* 199*44a87f08Sstephan The core API's WASM build does not support UTF16, but in 200*44a87f08Sstephan this app it's not an issue because the data are not crossing 201*44a87f08Sstephan JS/WASM boundaries. 202*44a87f08Sstephan */ 203*44a87f08Sstephan flags["utf16be"] = "Set text encoding to UTF-16BE"; 204*44a87f08Sstephan flags["utf16le"] = "Set text encoding to UTF-16LE"; 205*44a87f08Sstephan flags["verify"] = "Run additional verification steps."; 206*44a87f08Sstephan flags["without"] = "rowid Use WITHOUT ROWID where appropriate"; 207*44a87f08Sstephan const preselectedFlags = [ 208*44a87f08Sstephan 'singlethread', 209*44a87f08Sstephan 'memdb' 210*44a87f08Sstephan ]; 211*44a87f08Sstephan Object.keys(flags).sort().forEach(function(f){ 212*44a87f08Sstephan const opt = document.createElement('option'); 213*44a87f08Sstephan eFlags.appendChild(opt); 214*44a87f08Sstephan const lbl = nbspPad('--'+f)+flags[f]; 215*44a87f08Sstephan //opt.innerText = lbl; 216*44a87f08Sstephan opt.innerHTML = lbl; 217*44a87f08Sstephan opt.value = '--'+f; 218*44a87f08Sstephan if(preselectedFlags.indexOf(f) >= 0) opt.selected = true; 219*44a87f08Sstephan }); 220*44a87f08Sstephan 221*44a87f08Sstephan const cbReverseLog = E('#cb-reverse-log-order'); 222*44a87f08Sstephan const lblReverseLog = E('#lbl-reverse-log-order'); 223*44a87f08Sstephan if(cbReverseLog.checked){ 224*44a87f08Sstephan lblReverseLog.classList.add('warning'); 225*44a87f08Sstephan eOut.classList.add('reverse'); 226*44a87f08Sstephan } 227*44a87f08Sstephan cbReverseLog.addEventListener('change', function(){ 228*44a87f08Sstephan if(this.checked){ 229*44a87f08Sstephan eOut.classList.add('reverse'); 230*44a87f08Sstephan lblReverseLog.classList.add('warning'); 231*44a87f08Sstephan }else{ 232*44a87f08Sstephan eOut.classList.remove('reverse'); 233*44a87f08Sstephan lblReverseLog.classList.remove('warning'); 234*44a87f08Sstephan } 235*44a87f08Sstephan }, false); 236*44a87f08Sstephan updateSelectedFlags(); 237*44a87f08Sstephan } 238*44a87f08Sstephan E('#btn-output-clear').addEventListener('click', ()=>{ 239*44a87f08Sstephan eOut.innerText = ''; 240*44a87f08Sstephan }); 241*44a87f08Sstephan E('#btn-reset-flags').addEventListener('click',()=>{ 242*44a87f08Sstephan eFlags.value = ''; 243*44a87f08Sstephan updateSelectedFlags(); 244*44a87f08Sstephan }); 245*44a87f08Sstephan E('#btn-run').addEventListener('click',function(){ 246*44a87f08Sstephan log("Running speedtest1. UI controls will be disabled until it completes."); 247*44a87f08Sstephan mPost('run', getSelectedFlags()); 248*44a87f08Sstephan }); 249*44a87f08Sstephan 250*44a87f08Sstephan const eControls = E('#ui-controls'); 251*44a87f08Sstephan /** Update Emscripten-related UI elements while loading the module. */ 252*44a87f08Sstephan const updateLoadStatus = function f(text){ 253*44a87f08Sstephan if(!f.last){ 254*44a87f08Sstephan f.last = { text: '', step: 0 }; 255*44a87f08Sstephan const E = (cssSelector)=>document.querySelector(cssSelector); 256*44a87f08Sstephan f.ui = { 257*44a87f08Sstephan status: E('#module-status'), 258*44a87f08Sstephan progress: E('#module-progress'), 259*44a87f08Sstephan spinner: E('#module-spinner') 260*44a87f08Sstephan }; 261*44a87f08Sstephan } 262*44a87f08Sstephan if(text === f.last.text) return; 263*44a87f08Sstephan f.last.text = text; 264*44a87f08Sstephan if(f.ui.progress){ 265*44a87f08Sstephan f.ui.progress.value = f.last.step; 266*44a87f08Sstephan f.ui.progress.max = f.last.step + 1; 267*44a87f08Sstephan } 268*44a87f08Sstephan ++f.last.step; 269*44a87f08Sstephan if(text) { 270*44a87f08Sstephan f.ui.status.classList.remove('hidden'); 271*44a87f08Sstephan f.ui.status.innerText = text; 272*44a87f08Sstephan }else{ 273*44a87f08Sstephan if(f.ui.progress){ 274*44a87f08Sstephan f.ui.progress.remove(); 275*44a87f08Sstephan f.ui.spinner.remove(); 276*44a87f08Sstephan delete f.ui.progress; 277*44a87f08Sstephan delete f.ui.spinner; 278*44a87f08Sstephan } 279*44a87f08Sstephan f.ui.status.classList.add('hidden'); 280*44a87f08Sstephan } 281*44a87f08Sstephan }; 282*44a87f08Sstephan 283*44a87f08Sstephan log("Control-click the flags to (de)select multiple flags."); 284*44a87f08Sstephan logWarn("\nThe easiest way to try different optimization levels is, from this directory:\n"+ 285*44a87f08Sstephan " $ make clean; make -e emcc_opt='-O2' speedtest1\n"+ 286*44a87f08Sstephan "Then reload this page. -O2 seems to consistently produce the fastest results.\n"); 287*44a87f08Sstephan logWarn('\nAchtung: the Worker thread overhead slightly reduces the speed', 288*44a87f08Sstephan 'compared to running the same options via speedtest1.html.\n'+ 289*44a87f08Sstephan 'TODO: add a link in this app which launches the main-thread', 290*44a87f08Sstephan 'version with the same flags.\n'); 291*44a87f08Sstephan 292*44a87f08Sstephan W.onmessage = function(msg){ 293*44a87f08Sstephan msg = msg.data; 294*44a87f08Sstephan switch(msg.type){ 295*44a87f08Sstephan case 'ready': log("Worker is ready."); eControls.classList.remove('hidden'); break; 296*44a87f08Sstephan case 'stdout': log(msg.data); break; 297*44a87f08Sstephan case 'stdout': logErr(msg.data); break; 298*44a87f08Sstephan case 'run-start': 299*44a87f08Sstephan eControls.disabled = true; 300*44a87f08Sstephan log("Running speedtest1 with argv =",msg.data.join(' ')); 301*44a87f08Sstephan break; 302*44a87f08Sstephan case 'run-end': log("speedtest1 finished."); 303*44a87f08Sstephan eControls.disabled = false; 304*44a87f08Sstephan // app output is in msg.data 305*44a87f08Sstephan break; 306*44a87f08Sstephan case 'error': logErr(msg.data); break; 307*44a87f08Sstephan case 'load-status': updateLoadStatus(msg.data); break; 308*44a87f08Sstephan default: 309*44a87f08Sstephan logErr("Unhandled worker message type:",arguments[0]); 310*44a87f08Sstephan break; 311*44a87f08Sstephan } 312*44a87f08Sstephan }; 313*44a87f08Sstephan })();</script> 314*44a87f08Sstephan </body> 315*44a87f08Sstephan</html> 316