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