Add tests for the new code on this branch.
[sqlite.git] / ext / wasm / speedtest1-worker.html
blob8c9a77dc5e2d6a3f4f13121de5cf608f22c78244
1 <!doctype html>
2 <html lang="en-us">
3 <head>
4 <meta charset="utf-8">
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>
10 </head>
11 <body>
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>
18 <div class='center'>
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.
22 </div>
23 </figure>
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>
30 <div id='toolbar'>
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
35 </div>
36 </div>
37 <div class='toolbar-inner-vertical'>
38 <div id='toolbar-selected-flags'></div>
39 <div class='toolbar-inner-vertical'>
40 <span>&rarr; <a id='link-main-thread' href='#' target='speedtest-main'
41 title='Start speedtest1.html with the selected flags'>speedtest1</a>
42 </span>
43 <span class='hidden'>&rarr; <a id='link-wasmfs' href='#' target='speedtest-wasmfs'
44 title='Start speedtest1-wasmfs.html with the selected flags'>speedtest1-wasmfs</a>
45 </span>
46 <span>&rarr; <a id='link-kvvfs' href='#' target='speedtest-kvvfs'
47 title='Start kvvfs speedtest1 with the selected flags'>speedtest1-kvvfs</a>
48 </span>
49 </div>
50 </div>
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>
55 </div>
56 </div>
57 </fieldset>
58 <div>
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>
62 </span>
63 </div>
64 <div id='test-output'>
65 </div>
66 <div id='tips'>
67 <strong>Tips:</strong>
68 <ul>
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.
74 </li>
75 <li>The easiest way to try different optimization levels is,
76 from this directory:
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.
79 </li>
80 </ul>
81 </div>
82 <style>
83 #test-output {
84 white-space: break-spaces;
85 overflow: auto;
87 div#tips { margin-top: 1em; }
88 #toolbar {
89 display: flex;
90 flex-direction: row;
91 flex-wrap: wrap;
93 #toolbar > * {
94 margin: 0 0.5em;
96 .toolbar-inner-vertical {
97 display: flex;
98 flex-direction: column;
99 justify-content: space-between;
101 #toolbar-select {
102 display: flex;
103 flex-direction: column;
105 .toolbar-inner-vertical > *, #toolbar-select > * {
106 margin: 0.2em 0;
108 #select-flags > option {
109 white-space: pre;
110 font-family: monospace;
112 fieldset {
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 {
122 display: flex;
123 flex-direction: column;
124 font-family: monospace;
125 justify-content: flex-start;
127 </style>
128 <script>(function(){
129 'use strict';
130 const E = (sel)=>document.querySelector(sel);
131 const eOut = E('#test-output');
132 const log2 = function(cssClass,...args){
133 let ln;
134 if(1 || cssClass){
135 ln = document.createElement('div');
136 if(cssClass) ln.classList.add(cssClass);
137 ln.append(document.createTextNode(args.join(' ')));
138 }else{
139 // This doesn't work with the "reverse order" option!
140 ln = document.createTextNode(args.join(' ')+'\n');
142 eOut.append(ln);
144 const log = (...args)=>{
145 //console.log(...args);
146 log2('', ...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('&nbsp;');
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));
193 return f;
195 const updateSelectedFlags = function(){
196 eSelectedFlags.innerText = '';
197 const flags = getSelectedFlags();
198 flags.forEach(function(f){
199 const e = document.createElement('span');
200 e.innerText = f;
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
258 JS/WASM boundaries.
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',
266 '--singlethread'
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;
279 opt.innerHTML = lbl;
280 opt.value = f;
281 if(preselectedFlags.indexOf(f) >= 0) opt.selected = true;
282 });
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(){
290 if(this.checked){
291 eOut.classList.add('reverse');
292 lblReverseLog.classList.add('warning');
293 }else{
294 eOut.classList.remove('reverse');
295 lblReverseLog.classList.remove('warning');
297 }, false);
298 updateSelectedFlags();
300 E('#btn-output-clear').addEventListener('click', ()=>{
301 eOut.innerText = '';
303 E('#btn-reset-flags').addEventListener('click',()=>{
304 eFlags.value = '';
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){
315 if(!f.last){
316 f.last = { text: '', step: 0 };
317 const E = (cssSelector)=>document.querySelector(cssSelector);
318 f.ui = {
319 status: E('#module-status'),
320 progress: E('#module-progress'),
321 spinner: E('#module-spinner')
324 if(text === f.last.text) return;
325 f.last.text = text;
326 if(f.ui.progress){
327 f.ui.progress.value = f.last.step;
328 f.ui.progress.max = f.last.step + 1;
330 ++f.last.step;
331 if(text) {
332 f.ui.status.classList.remove('hidden');
333 f.ui.status.innerText = text;
334 }else{
335 if(f.ui.progress){
336 f.ui.progress.remove();
337 f.ui.spinner.remove();
338 delete f.ui.progress;
339 delete f.ui.spinner;
341 f.ui.status.classList.add('hidden');
345 W.onmessage = function(msg){
346 msg = msg.data;
347 switch(msg.type){
348 case 'ready':
349 log("Worker is ready.");
350 eControls.classList.remove('hidden');
351 break;
352 case 'stdout': log(msg.data); break;
353 case 'stderr': logErr(msg.data); break;
354 case 'run-start':
355 eControls.disabled = true;
356 log("Running speedtest1 with argv =",msg.data.join(' '));
357 break;
358 case 'run-end':
359 log("speedtest1 finished.");
360 eControls.disabled = false;
361 // app output is in msg.data
362 break;
363 case 'error': logErr(msg.data); break;
364 case 'load-status': updateLoadStatus(msg.data); break;
365 default:
366 logErr("Unhandled worker message type:",msg);
367 break;
370 })();</script>
371 </body>
372 </html>