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