diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index 25d1e98084..6a0835ece4 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -294,10 +294,12 @@ $(speedtest1): $(MAKE) -C ../.. speedtest1 speedtest1.sql: $(speedtest1) $(speedtest1) --script $@ -batch-sql.in := $(sort $(wildcard *.sql)) -batch-runner.list: $(batch-sql.in) $(MAKEFILE) speedtest1.sql +speedtest1-000.sql: + echo "select 1;" > $@ +batch-runner.list: $(MAKEFILE) speedtest1.sql speedtest1-000.sql bash split-speedtest1-script.sh speedtest1.sql - ls -1 *.sql | sort > $@ + ls -1 *.sql | grep -v speedtest1.sql | sort > $@ +CLEAN_FILES += batch-runner.list speedtest1*.sql batch: batch-runner.list ######################################################################## diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js index 5d4b19b5a9..2cfb478865 100644 --- a/ext/wasm/api/sqlite3-api-oo1.js +++ b/ext/wasm/api/sqlite3-api-oo1.js @@ -540,7 +540,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ if(isTA) wasm.heap8().set(arg.sql, pSql); else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false); wasm.setMemValue(pSql + sqlByteLen, 0/*NUL terminator*/); - while(wasm.getMemValue(pSql, 'i8') + while(pSql && wasm.getMemValue(pSql, 'i8') /* Maintenance reminder:^^^ _must_ be 'i8' or else we will very likely cause an endless loop. What that's doing is checking for a terminating NUL byte. If we @@ -548,8 +548,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ around the NUL terminator, and get stuck in and endless loop at the end of the SQL, endlessly re-preparing an empty statement. */ ){ - wasm.setMemValue(ppStmt, 0, wasm.ptrIR); - wasm.setMemValue(pzTail, 0, wasm.ptrIR); + wasm.setPtrValue(ppStmt, 0); + wasm.setPtrValue(pzTail, 0); DB.checkRc(this, capi.sqlite3_prepare_v3( this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail )); diff --git a/ext/wasm/batch-runner.html b/ext/wasm/batch-runner.html index f5031f8fe1..c91e591553 100644 --- a/ext/wasm/batch-runner.html +++ b/ext/wasm/batch-runner.html @@ -24,35 +24,48 @@
-

ACHTUNG: this file requires a generated input list +

+ This page is for running extracts from the output of speedtest --script. +

+

ACHTUNG: this file requires a generated input list file. Run "make batch" from this directory to generate it.

-

WARNING: if the WASMFS/OPFS layer crashes, this page may +

WARNING: if the WASMFS/OPFS layer crashes, this page may become completely unresponsive and need to be closed and reloaded to recover.


- - + + + +

+
(Log output is in reverse order, newest first!)
diff --git a/ext/wasm/batch-runner.js b/ext/wasm/batch-runner.js index b412dc2ced..0f5406f902 100644 --- a/ext/wasm/batch-runner.js +++ b/ext/wasm/batch-runner.js @@ -17,15 +17,19 @@ (function(){ const T = self.SqliteTestUtil; const toss = function(...args){throw new Error(args.join(' '))}; - const debug = console.debug.bind(console); + const warn = console.warn.bind(console); const App = { e: { output: document.querySelector('#test-output'), selSql: document.querySelector('#sql-select'), btnRun: document.querySelector('#sql-run'), - btnClear: document.querySelector('#output-clear') + btnRunNext: document.querySelector('#sql-run-next'), + btnRunRemaining: document.querySelector('#sql-run-remaining'), + btnClear: document.querySelector('#output-clear'), + btnReset: document.querySelector('#db-reset') }, + cache:{}, log: console.log.bind(console), warn: console.warn.bind(console), cls: function(){this.e.output.innerHTML = ''}, @@ -34,6 +38,7 @@ if(cssClass) ln.classList.add(cssClass); ln.append(document.createTextNode(args.join(' '))); this.e.output.append(ln); + //this.e.output.lastElementChild.scrollIntoViewIfNeeded(); }, logHtml: function(...args){ console.log(...args); @@ -44,29 +49,38 @@ if(1) this.logHtml2('error', ...args); }, - openDb: function(fn){ - if(this.pDb){ + openDb: function(fn, unlinkFirst=true){ + if(this.db && this.db.ptr){ toss("Already have an opened db."); } const capi = this.sqlite3.capi, wasm = capi.wasm; const stack = wasm.scopedAllocPush(); let pDb = 0; try{ + /*if(unlinkFirst && fn && ':memory:'!==fn){ + capi.sqlite3_wasm_vfs_unlink(fn); + }*/ const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; const ppDb = wasm.scopedAllocPtr(); const rc = capi.sqlite3_open_v2(fn, ppDb, oFlags, null); + if(rc) toss("sqlite3_open_v2() failed with code",rc); pDb = wasm.getPtrValue(ppDb) }finally{ wasm.scopedAllocPop(stack); } - this.logHtml("Opened db:",capi.sqlite3_db_filename(pDb, 'main')); - return this.pDb = pDb; + this.db = Object.create(null); + this.db.filename = fn; + this.db.ptr = pDb; + this.logHtml("Opened db:",fn); + return this.db.ptr; }, - closeDb: function(){ - if(this.pDb){ - this.sqlite3.capi.sqlite3_close_v2(this.pDb); - this.pDb = undefined; + closeDb: function(unlink=false){ + if(this.db && this.db.ptr){ + this.sqlite3.capi.sqlite3_close_v2(this.db.ptr); + this.logHtml("Closed db",this.db.filename); + if(unlink) capi.sqlite3_wasm_vfs_unlink(this.db.filename); + this.db.ptr = this.db.filename = undefined; } }, @@ -84,13 +98,15 @@ } if(!r.ok) toss("Loading",infile,"failed:",r.statusText); txt = await r.text(); + const warning = document.querySelector('#warn-list'); + if(warning) warning.remove(); }catch(e){ this.logErr(e.message); throw e; }finally{ this.blockControls(false); } - const list = txt.split('\n'); + const list = txt.split(/\n+/); let opt; if(0){ opt = document.createElement('option'); @@ -101,6 +117,7 @@ sel.appendChild(opt); } list.forEach(function(fn){ + if(!fn) return; opt = document.createElement('option'); opt.value = opt.innerText = fn; sel.appendChild(opt); @@ -109,7 +126,8 @@ }, /** Fetch ./fn and return its contents as a Uint8Array. */ - fetchFile: async function(fn){ + fetchFile: async function(fn, cacheIt=false){ + if(cacheIt && this.cache[fn]) return this.cache[fn]; this.logHtml("Fetching",fn,"..."); let sql; try { @@ -121,25 +139,28 @@ throw e; } this.logHtml("Fetched",sql.length,"bytes from",fn); + if(cacheIt) this.cache[fn] = sql; return sql; - }, + }/*fetchFile()*/, + /** Throws if the given sqlite3 result code is not 0. */ checkRc: function(rc){ - if(rc){ - toss("Prepare failed:",this.sqlite3.capi.sqlite3_errmsg(this.pDb)); + if(this.db.ptr && rc){ + toss("Prepare failed:",this.sqlite3.capi.sqlite3_errmsg(this.db.ptr)); } }, - blockControls: function(block){ - [ - this.e.selSql, this.e.btnRun, this.e.btnClear - ].forEach((e)=>e.disabled = block); + /** Disable or enable certain UI controls. */ + blockControls: function(disable){ + document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable); }, - + /** Fetch ./fn and eval it as an SQL blob. */ evalFile: async function(fn){ const sql = await this.fetchFile(fn); - this.logHtml("Running",fn,'...'); + const banner = "========================================"; + this.logHtml(banner, + "Running",fn,'('+sql.length,'bytes)...'); const capi = this.sqlite3.capi, wasm = capi.wasm; let pStmt = 0, pSqlBegin; const stack = wasm.scopedAllocPush(); @@ -147,35 +168,41 @@ metrics.prepTotal = metrics.stepTotal = 0; metrics.stmtCount = 0; this.blockControls(true); - // Use setTimeout() so that the above log messages run before the loop starts. - setTimeout((function(){ - metrics.timeStart = performance.now(); + if(this.gotErr){ + this.logErr("Cannot run ["+fn+"]: error cleanup is pending."); + return; + } + // Run this async so that the UI can be updated for the above header... + const ff = function(resolve, reject){ + metrics.evalFileStart = performance.now(); try { let t; let sqlByteLen = sql.byteLength; const [ppStmt, pzTail] = wasm.scopedAllocPtr(2); - pSqlBegin = wasm.alloc( sqlByteLen + 1/*SQL + NUL*/); + pSqlBegin = wasm.alloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed"); let pSql = pSqlBegin; const pSqlEnd = pSqlBegin + sqlByteLen; wasm.heap8().set(sql, pSql); wasm.setMemValue(pSql + sqlByteLen, 0); - while(wasm.getMemValue(pSql,'i8')){ - pStmt = 0; + let breaker = 0; + while(pSql && wasm.getMemValue(pSql,'i8')){ wasm.setPtrValue(ppStmt, 0); wasm.setPtrValue(pzTail, 0); t = performance.now(); let rc = capi.sqlite3_prepare_v3( - this.pDb, pSql, sqlByteLen, 0, ppStmt, pzTail + this.db.ptr, pSql, sqlByteLen, 0, ppStmt, pzTail ); metrics.prepTotal += performance.now() - t; this.checkRc(rc); - ++metrics.stmtCount; pStmt = wasm.getPtrValue(ppStmt); pSql = wasm.getPtrValue(pzTail); sqlByteLen = pSqlEnd - pSql; if(!pStmt) continue/*empty statement*/; + ++metrics.stmtCount; t = performance.now(); rc = capi.sqlite3_step(pStmt); + capi.sqlite3_finalize(pStmt); + pStmt = 0; metrics.stepTotal += performance.now() - t; switch(rc){ case capi.SQLITE_ROW: @@ -184,50 +211,88 @@ } } }catch(e){ - this.logErr(e.message); - throw e; + if(pStmt) capi.sqlite3_finalize(pStmt); + this.gotErr = e; + //throw e; + reject(e); + return; }finally{ wasm.dealloc(pSqlBegin); wasm.scopedAllocPop(stack); this.blockControls(false); } - metrics.timeEnd = performance.now(); - metrics.timeTotal = (metrics.timeEnd - metrics.timeStart); + metrics.evalFileEnd = performance.now(); + metrics.evalTimeTotal = (metrics.evalFileEnd - metrics.evalFileStart); this.logHtml("Metrics:");//,JSON.stringify(metrics, undefined, ' ')); this.logHtml("prepare() count:",metrics.stmtCount); this.logHtml("Time in prepare_v2():",metrics.prepTotal,"ms", "("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())"); this.logHtml("Time in step():",metrics.stepTotal,"ms", "("+(metrics.stepTotal / metrics.stmtCount),"ms per step())"); - this.logHtml("Total runtime:",metrics.timeTotal,"ms"); + this.logHtml("Total runtime:",metrics.evalTimeTotal,"ms"); this.logHtml("Overhead (time - prep - step):", - (metrics.timeTotal - metrics.prepTotal - metrics.stepTotal)+"ms"); - }.bind(this)), 10); - }, + (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms"); + this.logHtml(banner,"End of",fn); + resolve(this); + }.bind(this); + let p; + if(1){ + p = new Promise(function(res,rej){ + setTimeout(()=>ff(res, rej), 50)/*give UI a chance to output the "running" banner*/; + }); + }else{ + p = new Promise(ff); + } + return p.catch((e)=>this.logErr("Error via evalFile("+fn+"):",e.message)); + }/*evalFile()*/, run: function(sqlite3){ + delete this.run; this.sqlite3 = sqlite3; const capi = sqlite3.capi, wasm = capi.wasm; this.logHtml("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); this.logHtml("WASM heap size =",wasm.heap8().length); - this.logHtml("WARNING: if the WASMFS/OPFS layer crashes, this page may", - "become unresponsive and need to be closed and ", - "reloaded to recover."); + this.loadSqlList(); const pDir = capi.sqlite3_web_persistent_dir(); const dbFile = pDir ? pDir+"/speedtest.db" : ":memory:"; - if(pDir){ - // We initially need a clean db file, so... - capi.sqlite3_wasm_vfs_unlink(dbFile); + if(!pDir){ + document.querySelector('#warn-opfs').remove(); } - this.openDb(dbFile); - this.loadSqlList(); + this.openDb(dbFile, !!pDir); const who = this; this.e.btnClear.addEventListener('click', ()=>this.cls(), false); this.e.btnRun.addEventListener('click', function(){ if(!who.e.selSql.value) return; who.evalFile(who.e.selSql.value); }, false); - } + this.e.btnRunNext.addEventListener('click', function(){ + ++who.e.selSql.selectedIndex; + if(!who.e.selSql.value) return; + who.evalFile(who.e.selSql.value); + }, false); + this.e.btnReset.addEventListener('click', function(){ + const fn = who.db.filename; + if(fn){ + who.closeDb(true); + who.openDb(fn,true); + } + }, false); + this.e.btnRunRemaining.addEventListener('click', async function(){ + let v = who.e.selSql.value; + const timeStart = performance.now(); + while(v){ + await who.evalFile(v); + if(who.gotError){ + who.logErr("Error handling script",v,":",who.gotError.message); + break; + } + ++who.e.selSql.selectedIndex; + v = who.e.selSql.value; + } + const timeTotal = performance.now() - timeStart; + who.logHtml("Run-remaining time:",timeTotal,"ms ("+(timeTotal/1000/60)+" minute(s))"); + }, false); + }/*run()*/ }/*App*/; self.sqlite3TestModule.initSqlite3().then(function(theEmccModule){ diff --git a/manifest b/manifest index 6eb43c0ef2..bfcc12ac8f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\sdescriptions\sto\sthe\sspeedtest1\s'--\sbegin'\smarkers\sfor\spotential\sdisplay\sby\sthe\sdownstream\sJS\scode\swhich\suses\sthose\smarkers. -D 2022-08-29T17:41:16.571 +C Lots\sof\stweaking\sin\sbatch-runner.js.\sMinor\sinternal\sAPI\supdate\sin\sOO\s#1\sAPI. +D 2022-08-29T18:58:38.025 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -474,7 +474,7 @@ F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb F ext/wasm/EXPORTED_FUNCTIONS.fiddle db7a4602f043cf4a5e4135be3609a487f9f1c83f05778bfbdf93766be4541b96 F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02 -F ext/wasm/GNUmakefile 61c0d9dcda9ca174907f87770c9440b26408dc415d2e11a3cbcae017358fd08c +F ext/wasm/GNUmakefile cabfbb177d16c550442313416698e66dde575df27177d4ca3ccece5a66b37de4 F ext/wasm/README.md e1ee1e7c321c6a250bf78a84ca6f5882890a237a450ba5a0649c7a8399194c52 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 77ef4bcf37e362b9ad61f9c175dfc0f1b3e571563fb311b96581cf422ee6a8ec F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287 @@ -483,14 +483,14 @@ F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba814 F ext/wasm/api/post-js-header.js 0e853b78db83cb1c06b01663549e0e8b4f377f12f5a2d9a4a06cb776c003880b F ext/wasm/api/sqlite3-api-cleanup.js 1a12e64060c2cb0defd34656a76a9b1d7ed58459c290249bb31567c806fd44de F ext/wasm/api/sqlite3-api-glue.js 67ca83974410961953eeaa1dfed3518530d68381729ed1d27f95122f5baeabd3 -F ext/wasm/api/sqlite3-api-oo1.js 46a5151610076f45472c8d4fd31b728cc12e6fac4d44ea5c7cd1af087a906539 +F ext/wasm/api/sqlite3-api-oo1.js 183e863eedaba547ffe4981ab95797813b60da46749992bca400d2646e5ccd82 F ext/wasm/api/sqlite3-api-opfs.js 011799db398157cbd254264b6ebae00d7234b93d0e9e810345f213a5774993c0 F ext/wasm/api/sqlite3-api-prologue.js 2d5c5d3355f55eefe51922cec5bfedbec0f8300db98a17685ab7a34a03953c7a F ext/wasm/api/sqlite3-api-worker1.js 73579555563b789785ae83724014eaf31811073aad9be6596c8336ffb51edd71 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 F ext/wasm/api/sqlite3-wasm.c 0d81282eaeff2a6e9fc5c28a388c5c5b45cf25a9393992fa511ac009b27df982 -F ext/wasm/batch-runner.html f9068c4b4222d0c11ba0590391892e4d7576ef1a4fb76974ba0bd3b80c6217f9 -F ext/wasm/batch-runner.js 57f325e40812a89f8d47c918963f278d7a249d158cf0d245d75e74577af638c8 +F ext/wasm/batch-runner.html e5c3edd4a6c9359f6d9e6c99cb5f87f09007d98fa1c705ed3efa370abcd4323e +F ext/wasm/batch-runner.js 84a465acde760de81d0372415cce56737799876395a878c44a7d3ce5dfe29e39 F ext/wasm/common/SqliteTestUtil.js eb96275bed43fdb364b7d65bcded0ca5e22aaacff120d593d1385f852f486247 F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/common/testing.css 572cf1ffae0b6eb7ca63684d3392bf350217a07b90e7a896e4fa850700c989b0 @@ -2012,8 +2012,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 11f3ed61150c5940da6c157e5063e70c3aa0628dfd0023c47bb65b00af74ab1f -R 2ae8456ec9776838052861c3fb138f8f +P e5b7006f0f57f10a490d7eaeb7df77251a2f684602fed8ff161d8ce60033e7bc +R ac09921b66efbf8cc7311954674841d9 U stephan -Z 47d6dbc110cfca896ac7235ddcb7f7bf +Z 16cfbad53a69907d89a4919845ccdd35 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 99bc257577..622070996d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e5b7006f0f57f10a490d7eaeb7df77251a2f684602fed8ff161d8ce60033e7bc \ No newline at end of file +24b82b9504db3d8e1335c2300b133f897dc1a541026dc24be5b0ffd8be66d977 \ No newline at end of file