From 99cb0049ee98895e5fc0ee04c51b6681443a7020 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 25 Sep 2025 02:02:48 +0000 Subject: [PATCH] Consolidate the speedtest1 wasm build into the new mkwasmbuilds.c model. Remove the long-unused batch-runner JS tools. FossilOrigin-Name: 980c033c05bf37c0e8f5e82486ee99ba1294cc9c9e2087aaf83b64e5d0118b5f --- ext/wasm/GNUmakefile | 74 +--- ext/wasm/batch-runner-sahpool.html | 86 ---- ext/wasm/batch-runner-sahpool.js | 341 ---------------- ext/wasm/batch-runner.html | 90 ----- ext/wasm/batch-runner.js | 604 ----------------------------- ext/wasm/mkwasmbuilds.c | 162 ++++++-- manifest | 18 +- manifest.uuid | 2 +- 8 files changed, 148 insertions(+), 1229 deletions(-) delete mode 100644 ext/wasm/batch-runner-sahpool.html delete mode 100644 ext/wasm/batch-runner-sahpool.js delete mode 100644 ext/wasm/batch-runner.html delete mode 100644 ext/wasm/batch-runner.js diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index e536ebeba8..4da0627719 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -952,6 +952,15 @@ $(post-js.in.js): $(MKDIR.bld) $(post-jses.js) $(MAKEFILE) echo "/* END FILE: $$i */"; \ done > $@ +# +# speedtest1 decls needed before the $(bin.mkws)-generated makefile +# is included. +# +bin.speedtest1 = ../../speedtest1 +speedtest1.c = ../../test/speedtest1.c +speedtest1.c.in = $(speedtest1.c) $(sqlite3-wasm.c) +EXPORTED_FUNCTIONS.speedtest1 = $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1) + # # bin.mkwb is used for generating much of the makefile code for the # various wasm builds. It used to be generated in this makefile via a @@ -1039,7 +1048,6 @@ $(eval $(call gen-dwp,.js,.html,$(c-pp.D.vanilla))) $(eval $(call gen-dwp,.mjs,-esm.html,$(c-pp.D.esm))) all: demos - # # $(sqlite3.ext.in) = API-related files which are standalone # files, not part of the amalgamation. This list holds @@ -1049,19 +1057,6 @@ sqlite3.ext.js += $(dir.dout)/sqlite3-opfs-async-proxy.js $(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js @$(call b.call.cp,@,$<,$@) - -# -# Copy "external" files - those which are not part of the amalgamation -# - to $(dir.dout). -# -#define gen-extjs -#sqlite3.ext.js += $(dir.dout)/$(notdir $(1)) -#$(dir.dout)/$(notdir $(1)): $(1) -# @$(call b.cp,@,$(1),$@) -#endef -#sqlite3.ext.js = -#$(foreach X,$(sqlite3.ext.js.in),$(eval $(call gen-extjs,$(X)))) - # # Add a dep of $(sqlite3.ext.js) on every build's JS file. # The primary purpose of this is to force them to be copied early @@ -1071,34 +1066,13 @@ $(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js # $(foreach B,$(b.names),$(eval $(out.$(B).js): $(sqlite3.ext.js))) -######################################################################## -# batch-runner.js is part of one of the test apps which reads in SQL -# dumps generated by $(speedtest1) and executes them. -dir.sql = sql -speedtest1 = ../../speedtest1 -speedtest1.c = ../../test/speedtest1.c -speedtest1.sql = $(dir.sql)/speedtest1.sql -speedtest1.cliflags = --size 10 --big-transactions -$(speedtest1): - $(MAKE) -C ../.. speedtest1 -$(speedtest1.sql): $(speedtest1) $(MAKEFILE) - $(speedtest1) $(speedtest1.cliflags) --script $@ -batch-runner.list: $(MAKEFILE) $(speedtest1.sql) $(dir.sql)/000-mandelbrot.sql - bash split-speedtest1-script.sh $(dir.sql)/speedtest1.sql - ls -1 $(dir.sql)/*.sql | grep -v speedtest1.sql | sort > $@ -clean-batch: - rm -f batch-runner.list $(dir.sql)/speedtest1*.sql -# ^^^ we don't do this along with 'clean' because we clean/rebuild on -# a regular basis with different -Ox flags and rebuilding the batch -# pieces each time is an unnecessary time sink. -batch: batch-runner.list -#all: batch -# end batch-runner.js ######################################################################## # Wasmified speedtest1 is our primary benchmarking tool. # # emcc.speedtest1.common = emcc flags used by multiple builds of speedtest1 # emcc.speedtest1 = emcc flags used by main build of speedtest1 +# +# These flags get applied via $(bin.mkwb). emcc.speedtest1.common = $(emcc_opt_full) emcc.speedtest1 = -I. -I$(dir $(sqlite3.canonical.c)) emcc.speedtest1 += -sENVIRONMENT=web @@ -1113,7 +1087,6 @@ emcc.speedtest1.common += -Wno-limited-postlink-optimizations emcc.speedtest1.common += -Wno-unused-main # ^^^^ -Wno-unused-main is for emcc 3.1.52+. speedtest1 has a wasm_main() which is # exported and called by the JS code. -EXPORTED_FUNCTIONS.speedtest1 = $(abspath $(dir.tmp)/EXPORTED_FUNCTIONS.speedtest1) emcc.speedtest1.common += -sSTACK_SIZE=512KB emcc.speedtest1.common += -sEXPORTED_FUNCTIONS=@$(EXPORTED_FUNCTIONS.speedtest1) emcc.speedtest1.common += $(emcc.exportedRuntimeMethods) @@ -1123,7 +1096,6 @@ emcc.speedtest1.common += --minify 0 emcc.speedtest1.common += -sEXPORT_NAME=$(sqlite3.js.init-func) emcc.speedtest1.common += -sWASM_BIGINT=$(emcc.WASM_BIGINT) emcc.speedtest1.common += -sMEMORY64=$(emcc.MEMORY64) - speedtest1.exit-runtime0 = -sEXIT_RUNTIME=0 speedtest1.exit-runtime1 = -sEXIT_RUNTIME=1 # Re -sEXIT_RUNTIME=1 vs 0: if it's 1 and speedtest1 crashes, we get @@ -1147,28 +1119,6 @@ $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.core) @echo "Making $@ ..." @$(call b.call.mkdir@) @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@ -emcc.flags.speedtest1 = $(cflags.common) -DSQLITE_SPEEDTEST1_WASM -speedtest1.cfiles = $(speedtest1.c) $(sqlite3-wasm.c) -$(out.speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \ - $(pre-post.speedtest1.deps) \ - $(EXPORTED_FUNCTIONS.speedtest1) - @$(call b.echo,speedtest1,$(emo.compile) building ...) - @$(call b.call.mkdir@) - $(b.cmd@)$(bin.emcc) \ - $(emcc.speedtest1) \ - $(emcc.speedtest1.common) \ - $(emcc.flags.speedtest1) $(pre-post.speedtest1.flags) \ - $(SQLITE_OPT) \ - -USQLITE_WASM_BARE_BONES \ - -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \ - $(speedtest1.exit-runtime0) \ - -o $@ $(speedtest1.cfiles) -lm - @chmod -x $(basename $@).wasm - @$(call b.call.wasm-strip,speedtest1) - @$(call b.do.wasm-opt,speedtest1) - @$(call b.call.strip-emcc-js-cruft,$(logtag.speedtest1)) - @ls -la $@ $(speedtest1.wasm) - speedtest1: $(out.speedtest1.js) # end speedtest1.js ######################################################################## @@ -1227,7 +1177,7 @@ $(eval $(call b.eval.c-pp,test,tester1-worker.c-pp.html,tester1-worker.html)) $(eval $(call b.eval.c-pp,test,tester1-worker.c-pp.html,tester1-worker-64bit.html,$(c-pp.D.64bit))) tester: tester1-worker.html tester1-worker-64bit.html -all: tester +all: tester1 ######################################################################## # Convenience rules to rebuild with various -Ox levels. Much diff --git a/ext/wasm/batch-runner-sahpool.html b/ext/wasm/batch-runner-sahpool.html deleted file mode 100644 index ad7e7b5408..0000000000 --- a/ext/wasm/batch-runner-sahpool.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - sqlite3-api batch SQL runner for the SAHPool VFS - - -
sqlite3-api batch SQL runner for the SAHPool VFS
-
- - - - -
-
- - - - diff --git a/ext/wasm/batch-runner-sahpool.js b/ext/wasm/batch-runner-sahpool.js deleted file mode 100644 index dfa5044a9e..0000000000 --- a/ext/wasm/batch-runner-sahpool.js +++ /dev/null @@ -1,341 +0,0 @@ -/* - 2023-11-30 - - The author disclaims copyright to this source code. In place of a - legal notice, here is a blessing: - - * May you do good and not evil. - * May you find forgiveness for yourself and forgive others. - * May you share freely, never taking more than you give. - - *********************************************************************** - - A basic batch SQL runner for the SAHPool VFS. This file must be run in - a worker thread. This is not a full-featured app, just a way to get some - measurements for batch execution of SQL for the OPFS SAH Pool VFS. -*/ -'use strict'; - -const wMsg = function(msgType,...args){ - postMessage({ - type: msgType, - data: args - }); -}; -const toss = function(...args){throw new Error(args.join(' '))}; -const warn = (...args)=>{ wMsg('warn',...args); }; -const error = (...args)=>{ wMsg('error',...args); }; -const log = (...args)=>{ wMsg('stdout',...args); } -let sqlite3; -const urlParams = new URL(globalThis.location.href).searchParams; -const cacheSize = (()=>{ - if(urlParams.has('cachesize')) return +urlParams.get('cachesize'); - return 200; -})(); - - -/** Throws if the given sqlite3 result code is not 0. */ -const checkSqliteRc = (dbh,rc)=>{ - if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh)); -}; - -const sqlToDrop = [ - "SELECT type,name FROM sqlite_schema ", - "WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ", - "AND name NOT LIKE '\\_%' escape '\\'" -].join(''); - -const clearDbSqlite = function(db){ - // This would be SO much easier with the oo1 API, but we specifically want to - // inject metrics we can't get via that API, and we cannot reliably (OPFS) - // open the same DB twice to clear it using that API, so... - const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle); - log("reset db rc =",rc,db.id, db.filename); -}; - -const App = { - db: undefined, - cache:Object.create(null), - log: log, - warn: warn, - error: error, - metrics: { - fileCount: 0, - runTimeMs: 0, - prepareTimeMs: 0, - stepTimeMs: 0, - stmtCount: 0, - strcpyMs: 0, - sqlBytes: 0 - }, - fileList: undefined, - execSql: async function(name,sql){ - const db = this.db; - const banner = "========================================"; - this.log(banner, - "Running",name,'('+sql.length,'bytes)'); - const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm; - let pStmt = 0, pSqlBegin; - const metrics = db.metrics = Object.create(null); - metrics.prepTotal = metrics.stepTotal = 0; - metrics.stmtCount = 0; - metrics.malloc = 0; - metrics.strcpy = 0; - if(this.gotErr){ - this.error("Cannot run SQL: error cleanup is pending."); - return; - } - // Run this async so that the UI can be updated for the above header... - const endRun = ()=>{ - metrics.evalSqlEnd = performance.now(); - metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart); - this.log("metrics:",JSON.stringify(metrics, undefined, ' ')); - this.log("prepare() count:",metrics.stmtCount); - this.log("Time in prepare_v2():",metrics.prepTotal,"ms", - "("+(metrics.prepTotal / metrics.stmtCount),"ms per prepare())"); - this.log("Time in step():",metrics.stepTotal,"ms", - "("+(metrics.stepTotal / metrics.stmtCount),"ms per step())"); - this.log("Total runtime:",metrics.evalTimeTotal,"ms"); - this.log("Overhead (time - prep - step):", - (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms"); - this.log(banner,"End of",name); - this.metrics.prepareTimeMs += metrics.prepTotal; - this.metrics.stepTimeMs += metrics.stepTotal; - this.metrics.stmtCount += metrics.stmtCount; - this.metrics.strcpyMs += metrics.strcpy; - this.metrics.sqlBytes += sql.length; - }; - - const runner = function(resolve, reject){ - ++this.metrics.fileCount; - metrics.evalSqlStart = performance.now(); - const stack = wasm.scopedAllocPush(); - try { - let t, rc; - let sqlByteLen = sql.byteLength; - const [ppStmt, pzTail] = wasm.scopedAllocPtr(2); - t = performance.now(); - pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed"); - metrics.malloc = performance.now() - t; - metrics.byteLength = sqlByteLen; - let pSql = pSqlBegin; - const pSqlEnd = pSqlBegin + sqlByteLen; - t = performance.now(); - wasm.heap8().set(sql, pSql); - wasm.poke(pSql + sqlByteLen, 0); - //log("SQL:",wasm.cstrToJs(pSql)); - metrics.strcpy = performance.now() - t; - let breaker = 0; - while(pSql && wasm.peek8(pSql)){ - wasm.pokePtr(ppStmt, 0); - wasm.pokePtr(pzTail, 0); - t = performance.now(); - rc = capi.sqlite3_prepare_v2( - db.handle, pSql, sqlByteLen, ppStmt, pzTail - ); - metrics.prepTotal += performance.now() - t; - checkSqliteRc(db.handle, rc); - pStmt = wasm.peekPtr(ppStmt); - pSql = wasm.peekPtr(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: - case capi.SQLITE_DONE: break; - default: checkSqliteRc(db.handle, rc); toss("Not reached."); - } - } - resolve(this); - }catch(e){ - if(pStmt) capi.sqlite3_finalize(pStmt); - this.gotErr = e; - reject(e); - }finally{ - capi.sqlite3_exec(db.handle,"rollback;",0,0,0); - wasm.scopedAllocPop(stack); - } - }.bind(this); - const p = new Promise(runner); - return p.catch( - (e)=>this.error("Error via execSql("+name+",...):",e.message) - ).finally(()=>{ - endRun(); - }); - }, - - /** - Loads batch-runner.list and populates the selection list from - it. Returns a promise which resolves to nothing in particular - when it completes. Only intended to be run once at the start - of the app. - */ - loadSqlList: async function(){ - const infile = 'batch-runner.list'; - this.log("Loading list of SQL files:", infile); - let txt; - try{ - const r = await fetch(infile); - if(404 === r.status){ - toss("Missing file '"+infile+"'."); - } - if(!r.ok) toss("Loading",infile,"failed:",r.statusText); - txt = await r.text(); - }catch(e){ - this.error(e.message); - throw e; - } - App.fileList = txt.split(/\n+/).filter(x=>!!x); - this.log("Loaded",infile); - }, - - /** Fetch ./fn and return its contents as a Uint8Array. */ - fetchFile: async function(fn, cacheIt=false){ - if(cacheIt && this.cache[fn]) return this.cache[fn]; - this.log("Fetching",fn,"..."); - let sql; - try { - const r = await fetch(fn); - if(!r.ok) toss("Fetch failed:",r.statusText); - sql = new Uint8Array(await r.arrayBuffer()); - }catch(e){ - this.error(e.message); - throw e; - } - this.log("Fetched",sql.length,"bytes from",fn); - if(cacheIt) this.cache[fn] = sql; - return sql; - }/*fetchFile()*/, - - /** - Converts this.metrics() to a form which is suitable for easy conversion to - CSV. It returns an array of arrays. The first sub-array is the column names. - The 2nd and subsequent are the values, one per test file (only the most recent - metrics are kept for any given file). - */ - metricsToArrays: function(){ - const rc = []; - Object.keys(this.dbs).sort().forEach((k)=>{ - const d = this.dbs[k]; - const m = d.metrics; - delete m.evalSqlStart; - delete m.evalSqlEnd; - const mk = Object.keys(m).sort(); - if(!rc.length){ - rc.push(['db', ...mk]); - } - const row = [k.split('/').pop()/*remove dir prefix from filename*/]; - rc.push(row); - row.push(...mk.map((kk)=>m[kk])); - }); - return rc; - }, - - metricsToBlob: function(colSeparator='\t'){ - const ar = [], ma = this.metricsToArrays(); - if(!ma.length){ - this.error("Metrics are empty. Run something."); - return; - } - ma.forEach(function(row){ - ar.push(row.join(colSeparator),'\n'); - }); - return new Blob(ar); - }, - - /** - Fetch file fn and eval it as an SQL blob. This is an async - operation and returns a Promise which resolves to this - object on success. - */ - evalFile: async function(fn){ - const sql = await this.fetchFile(fn); - return this.execSql(fn,sql); - }/*evalFile()*/, - - /** - Fetches the handle of the db associated with - this.e.selImpl.value, opening it if needed. - */ - initDb: function(){ - const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm; - const stack = wasm.scopedAllocPush(); - let pDb = 0; - const d = Object.create(null); - d.filename = "/batch.db"; - try{ - const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; - const ppDb = wasm.scopedAllocPtr(); - const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, this.PoolUtil.vfsName); - pDb = wasm.peekPtr(ppDb) - if(rc) toss("sqlite3_open_v2() failed with code",rc); - capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0); - this.log("cache_size =",cacheSize); - }catch(e){ - if(pDb) capi.sqlite3_close_v2(pDb); - throw e; - }finally{ - wasm.scopedAllocPop(stack); - } - d.handle = pDb; - this.log("Opened db:",d.filename,'@',d.handle); - return d; - }, - - closeDb: function(){ - if(this.db.handle){ - this.sqlite3.capi.sqlite3_close_v2(this.db.handle); - this.db.handle = undefined; - } - }, - - run: async function(sqlite3){ - delete this.run; - this.sqlite3 = sqlite3; - const capi = sqlite3.capi, wasm = sqlite3.wasm; - this.log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); - this.log("WASM heap size =",wasm.heap8().length); - let timeStart; - sqlite3.installOpfsSAHPoolVfs({ - clearOnInit: true, initialCapacity: 4, - name: 'batch-sahpool', - verbosity: 2 - }).then(PoolUtil=>{ - App.PoolUtil = PoolUtil; - App.db = App.initDb(); - }) - .then(async ()=>this.loadSqlList()) - .then(async ()=>{ - timeStart = performance.now(); - for(let i = 0; i < App.fileList.length; ++i){ - const fn = App.fileList[i]; - await App.evalFile(fn); - if(App.gotErr) throw App.gotErr; - } - }) - .then(()=>{ - App.metrics.runTimeMs = performance.now() - timeStart; - App.log("total metrics:",JSON.stringify(App.metrics, undefined, ' ')); - App.log("Reload the page to run this again."); - App.closeDb(); - App.PoolUtil.removeVfs(); - }) - .catch(e=>this.error("ERROR:",e)); - }/*run()*/ -}/*App*/; - -let sqlite3Js = 'sqlite3.js'; -if(urlParams.has('sqlite3.dir')){ - sqlite3Js = urlParams.get('sqlite3.dir') + '/' + sqlite3Js; -} -importScripts(sqlite3Js); -globalThis.sqlite3InitModule().then(async function(sqlite3_){ - log("Done initializing. Running batch runner..."); - sqlite3 = sqlite3_; - App.run(sqlite3_); -}); diff --git a/ext/wasm/batch-runner.html b/ext/wasm/batch-runner.html deleted file mode 100644 index 5258f9597e..0000000000 --- a/ext/wasm/batch-runner.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - sqlite3-api batch SQL runner - - -
sqlite3-api batch SQL runner
- -
-
-
Initializing app...
-
- 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. -
-
-
Downloading...
-
- -
-

- This page is for batch-running extracts from the output - of speedtest1 --script, as well as other standalone SQL - scripts. -

-

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

- - -
-
-
- - - - - - - - - - - -
- -
- - - - -
- - - - - - diff --git a/ext/wasm/batch-runner.js b/ext/wasm/batch-runner.js deleted file mode 100644 index e7a322b7f0..0000000000 --- a/ext/wasm/batch-runner.js +++ /dev/null @@ -1,604 +0,0 @@ -/* - 2022-08-29 - - The author disclaims copyright to this source code. In place of a - legal notice, here is a blessing: - - * May you do good and not evil. - * May you find forgiveness for yourself and forgive others. - * May you share freely, never taking more than you give. - - *********************************************************************** - - A basic batch SQL runner for sqlite3-api.js. This file must be run in - main JS thread and sqlite3.js must have been loaded before it. -*/ -'use strict'; -(function(){ - const toss = function(...args){throw new Error(args.join(' '))}; - const warn = console.warn.bind(console); - let sqlite3; - const urlParams = new URL(self.location.href).searchParams; - const cacheSize = (()=>{ - if(urlParams.has('cachesize')) return +urlParams.get('cachesize'); - return 200; - })(); - - /** Throws if the given sqlite3 result code is not 0. */ - const checkSqliteRc = (dbh,rc)=>{ - if(rc) toss("Prepare failed:",sqlite3.capi.sqlite3_errmsg(dbh)); - }; - - const sqlToDrop = [ - "SELECT type,name FROM sqlite_schema ", - "WHERE name NOT LIKE 'sqlite\\_%' escape '\\' ", - "AND name NOT LIKE '\\_%' escape '\\'" - ].join(''); - - const clearDbWebSQL = function(db){ - db.handle.transaction(function(tx){ - const onErr = (e)=>console.error(e); - const callback = function(tx, result){ - const rows = result.rows; - let i, n; - i = n = rows.length; - while(i--){ - const row = rows.item(i); - const name = JSON.stringify(row.name); - const type = row.type; - switch(type){ - case 'index': case 'table': - case 'trigger': case 'view': { - const sql2 = 'DROP '+type+' '+name; - tx.executeSql(sql2, [], ()=>{}, onErr); - break; - } - default: - warn("Unhandled db entry type:",type,'name =',name); - break; - } - } - }; - tx.executeSql(sqlToDrop, [], callback, onErr); - db.handle.changeVersion(db.handle.version, "", ()=>{}, onErr, ()=>{}); - }); - }; - - const clearDbSqlite = function(db){ - // This would be SO much easier with the oo1 API, but we specifically want to - // inject metrics we can't get via that API, and we cannot reliably (OPFS) - // open the same DB twice to clear it using that API, so... - const rc = sqlite3.wasm.exports.sqlite3_wasm_db_reset(db.handle); - App.logHtml("reset db rc =",rc,db.id, db.filename); - }; - - const E = (s)=>document.querySelector(s); - const App = { - e: { - output: E('#test-output'), - selSql: E('#sql-select'), - btnRun: E('#sql-run'), - btnRunNext: E('#sql-run-next'), - btnRunRemaining: E('#sql-run-remaining'), - btnExportMetrics: E('#export-metrics'), - btnClear: E('#output-clear'), - btnReset: E('#db-reset'), - cbReverseLog: E('#cb-reverse-log-order'), - selImpl: E('#select-impl'), - fsToolbar: E('#toolbar') - }, - db: Object.create(null), - dbs: Object.create(null), - cache:{}, - metrics: { - fileCount: 0, - runTimeMs: 0, - prepareTimeMs: 0, - stepTimeMs: 0, - stmtCount: 0, - strcpyMs: 0, - sqlBytes: 0 - }, - log: console.log.bind(console), - warn: console.warn.bind(console), - cls: function(){this.e.output.innerHTML = ''}, - logHtml2: function(cssClass,...args){ - const ln = document.createElement('div'); - 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); - if(1) this.logHtml2('', ...args); - }, - logErr: function(...args){ - console.error(...args); - if(1) this.logHtml2('error', ...args); - }, - - execSql: async function(name,sql){ - const db = this.getSelectedDb(); - const banner = "========================================"; - this.logHtml(banner, - "Running",name,'('+sql.length,'bytes) using',db.id); - const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm; - let pStmt = 0, pSqlBegin; - const metrics = db.metrics = Object.create(null); - metrics.prepTotal = metrics.stepTotal = 0; - metrics.stmtCount = 0; - metrics.malloc = 0; - metrics.strcpy = 0; - this.blockControls(true); - if(this.gotErr){ - this.logErr("Cannot run SQL: error cleanup is pending."); - return; - } - // Run this async so that the UI can be updated for the above header... - const endRun = ()=>{ - metrics.evalSqlEnd = performance.now(); - metrics.evalTimeTotal = (metrics.evalSqlEnd - metrics.evalSqlStart); - this.logHtml(db.id,"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.evalTimeTotal,"ms"); - this.logHtml("Overhead (time - prep - step):", - (metrics.evalTimeTotal - metrics.prepTotal - metrics.stepTotal)+"ms"); - this.logHtml(banner,"End of",name); - this.metrics.prepareTimeMs += metrics.prepTotal; - this.metrics.stepTimeMs += metrics.stepTotal; - this.metrics.stmtCount += metrics.stmtCount; - this.metrics.strcpyMs += metrics.strcpy; - this.metrics.sqlBytes += sql.length; - }; - - let runner; - if('websql'===db.id){ - const who = this; - runner = function(resolve, reject){ - /* WebSQL cannot execute multiple statements, nor can it execute SQL without - an explicit transaction. Thus we have to do some fragile surgery on the - input SQL. Since we're only expecting carefully curated inputs, the hope is - that this will suffice. PS: it also can't run most SQL functions, e.g. even - instr() results in "not authorized". */ - if('string'!==typeof sql){ // assume TypedArray - sql = new TextDecoder().decode(sql); - } - sql = sql.replace(/-- [^\n]+\n/g,''); // comment lines interfere with our split() - const sqls = sql.split(/;+\n/); - const rxBegin = /^BEGIN/i, rxCommit = /^COMMIT/i; - try { - const nextSql = ()=>{ - let x = sqls.shift(); - while(sqls.length && !x) x = sqls.shift(); - return x && x.trim(); - }; - const who = this; - const transaction = function(tx){ - try { - let s; - /* Try to approximate the spirit of the input scripts - by running batches bound by BEGIN/COMMIT statements. */ - for(s = nextSql(); !!s; s = nextSql()){ - if(rxBegin.test(s)) continue; - else if(rxCommit.test(s)) break; - //console.log("websql sql again",sqls.length, s); - ++metrics.stmtCount; - const t = performance.now(); - tx.executeSql(s,[], ()=>{}, (t,e)=>{ - console.error("WebSQL error",e,"SQL =",s); - who.logErr(e.message); - //throw e; - return false; - }); - metrics.stepTotal += performance.now() - t; - } - }catch(e){ - who.logErr("transaction():",e.message); - throw e; - } - }; - const n = sqls.length; - const nextBatch = function(){ - if(sqls.length){ - console.log("websql sqls.length",sqls.length,'of',n); - db.handle.transaction(transaction, (e)=>{ - who.logErr("Ignoring and contiuing:",e.message) - //reject(e); - return false; - }, nextBatch); - }else{ - resolve(who); - } - }; - metrics.evalSqlStart = performance.now(); - nextBatch(); - }catch(e){ - //this.gotErr = e; - console.error("websql error:",e); - who.logErr(e.message); - //reject(e); - } - }.bind(this); - }else{/*sqlite3 db...*/ - runner = function(resolve, reject){ - ++this.metrics.fileCount; - metrics.evalSqlStart = performance.now(); - const stack = wasm.scopedAllocPush(); - try { - let t; - let sqlByteLen = sql.byteLength; - const [ppStmt, pzTail] = wasm.scopedAllocPtr(2); - t = performance.now(); - pSqlBegin = wasm.scopedAlloc( sqlByteLen + 1/*SQL + NUL*/) || toss("alloc(",sqlByteLen,") failed"); - metrics.malloc = performance.now() - t; - metrics.byteLength = sqlByteLen; - let pSql = pSqlBegin; - const pSqlEnd = pSqlBegin + sqlByteLen; - t = performance.now(); - wasm.heap8().set(sql, pSql); - wasm.poke(pSql + sqlByteLen, 0); - metrics.strcpy = performance.now() - t; - let breaker = 0; - while(pSql && wasm.peek(pSql,'i8')){ - wasm.pokePtr(ppStmt, 0); - wasm.pokePtr(pzTail, 0); - t = performance.now(); - let rc = capi.sqlite3_prepare_v3( - db.handle, pSql, sqlByteLen, 0, ppStmt, pzTail - ); - metrics.prepTotal += performance.now() - t; - checkSqliteRc(db.handle, rc); - pStmt = wasm.peekPtr(ppStmt); - pSql = wasm.peekPtr(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: - case capi.SQLITE_DONE: break; - default: checkSqliteRc(db.handle, rc); toss("Not reached."); - } - } - resolve(this); - }catch(e){ - if(pStmt) capi.sqlite3_finalize(pStmt); - //this.gotErr = e; - reject(e); - }finally{ - capi.sqlite3_exec(db.handle,"rollback;",0,0,0); - wasm.scopedAllocPop(stack); - } - }.bind(this); - } - let p; - if(1){ - p = new Promise(function(res,rej){ - setTimeout(()=>runner(res, rej), 0)/*give UI a chance to output the "running" banner*/; - }); - }else{ - p = new Promise(runner); - } - return p.catch( - (e)=>this.logErr("Error via execSql("+name+",...):",e.message) - ).finally(()=>{ - endRun(); - this.blockControls(false); - }); - }, - - clearDb: function(){ - const db = this.getSelectedDb(); - if('websql'===db.id){ - this.logErr("TODO: clear websql db."); - return; - } - if(!db.handle) return; - const capi = this.sqlite3, wasm = this.sqlite3.wasm; - //const scope = wasm.scopedAllocPush( - this.logErr("TODO: clear db"); - }, - - /** - Loads batch-runner.list and populates the selection list from - it. Returns a promise which resolves to nothing in particular - when it completes. Only intended to be run once at the start - of the app. - */ - loadSqlList: async function(){ - const sel = this.e.selSql; - sel.innerHTML = ''; - this.blockControls(true); - const infile = 'batch-runner.list'; - this.logHtml("Loading list of SQL files:", infile); - let txt; - try{ - const r = await fetch(infile); - if(404 === r.status){ - toss("Missing file '"+infile+"'."); - } - if(!r.ok) toss("Loading",infile,"failed:",r.statusText); - txt = await r.text(); - const warning = E('#warn-list'); - if(warning) warning.remove(); - }catch(e){ - this.logErr(e.message); - throw e; - }finally{ - this.blockControls(false); - } - const list = txt.split(/\n+/); - let opt; - if(0){ - opt = document.createElement('option'); - opt.innerText = "Select file to evaluate..."; - opt.value = ''; - opt.disabled = true; - opt.selected = true; - sel.appendChild(opt); - } - list.forEach(function(fn){ - if(!fn) return; - opt = document.createElement('option'); - opt.value = fn; - opt.innerText = fn.split('/').pop(); - sel.appendChild(opt); - }); - this.logHtml("Loaded",infile); - }, - - /** Fetch ./fn and return its contents as a Uint8Array. */ - fetchFile: async function(fn, cacheIt=false){ - if(cacheIt && this.cache[fn]) return this.cache[fn]; - this.logHtml("Fetching",fn,"..."); - let sql; - try { - const r = await fetch(fn); - if(!r.ok) toss("Fetch failed:",r.statusText); - sql = new Uint8Array(await r.arrayBuffer()); - }catch(e){ - this.logErr(e.message); - throw e; - } - this.logHtml("Fetched",sql.length,"bytes from",fn); - if(cacheIt) this.cache[fn] = sql; - return sql; - }/*fetchFile()*/, - - /** Disable or enable certain UI controls. */ - blockControls: function(disable){ - //document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable); - this.e.fsToolbar.disabled = disable; - }, - - /** - Converts this.metrics() to a form which is suitable for easy conversion to - CSV. It returns an array of arrays. The first sub-array is the column names. - The 2nd and subsequent are the values, one per test file (only the most recent - metrics are kept for any given file). - */ - metricsToArrays: function(){ - const rc = []; - Object.keys(this.dbs).sort().forEach((k)=>{ - const d = this.dbs[k]; - const m = d.metrics; - delete m.evalSqlStart; - delete m.evalSqlEnd; - const mk = Object.keys(m).sort(); - if(!rc.length){ - rc.push(['db', ...mk]); - } - const row = [k.split('/').pop()/*remove dir prefix from filename*/]; - rc.push(row); - row.push(...mk.map((kk)=>m[kk])); - }); - return rc; - }, - - metricsToBlob: function(colSeparator='\t'){ - const ar = [], ma = this.metricsToArrays(); - if(!ma.length){ - this.logErr("Metrics are empty. Run something."); - return; - } - ma.forEach(function(row){ - ar.push(row.join(colSeparator),'\n'); - }); - return new Blob(ar); - }, - - downloadMetrics: function(){ - const b = this.metricsToBlob(); - if(!b) return; - const url = URL.createObjectURL(b); - const a = document.createElement('a'); - a.href = url; - a.download = 'batch-runner-js-'+((new Date().getTime()/1000) | 0)+'.csv'; - this.logHtml("Triggering download of",a.download); - document.body.appendChild(a); - a.click(); - setTimeout(()=>{ - document.body.removeChild(a); - URL.revokeObjectURL(url); - }, 500); - }, - - /** - Fetch file fn and eval it as an SQL blob. This is an async - operation and returns a Promise which resolves to this - object on success. - */ - evalFile: async function(fn){ - const sql = await this.fetchFile(fn); - return this.execSql(fn,sql); - }/*evalFile()*/, - - /** - Clears all DB tables in all _opened_ databases. Because of - disparities between backends, we cannot simply "unlink" the - databases to clean them up. - */ - clearStorage: function(onlySelectedDb=false){ - const list = onlySelectedDb - ? [('boolean'===typeof onlySelectedDb) - ? this.dbs[this.e.selImpl.value] - : onlySelectedDb] - : Object.values(this.dbs); - for(let db of list){ - if(db && db.handle){ - this.logHtml("Clearing db",db.id); - db.clear(); - } - } - }, - - /** - Fetches the handle of the db associated with - this.e.selImpl.value, opening it if needed. - */ - getSelectedDb: function(){ - if(!this.dbs.memdb){ - for(let opt of this.e.selImpl.options){ - const d = this.dbs[opt.value] = Object.create(null); - d.id = opt.value; - switch(d.id){ - case 'virtualfs': - d.filename = 'file:/virtualfs.sqlite3?vfs=unix-none'; - break; - case 'memdb': - d.filename = ':memory:'; - break; - case 'wasmfs-opfs': - d.filename = 'file:'+( - this.sqlite3.capi.sqlite3_wasmfs_opfs_dir() - )+'/wasmfs-opfs.sqlite3b'; - break; - case 'websql': - d.filename = 'websql.db'; - break; - default: - this.logErr("Unhandled db selection option (see details in the console).",opt); - toss("Unhandled db init option"); - } - } - }/*first-time init*/ - const dbId = this.e.selImpl.value; - const d = this.dbs[dbId]; - if(d.handle) return d; - if('websql' === dbId){ - d.handle = self.openDatabase('batch-runner', '0.1', 'foo', 1024 * 1024 * 50); - d.clear = ()=>clearDbWebSQL(d); - d.handle.transaction(function(tx){ - tx.executeSql("PRAGMA cache_size="+cacheSize); - App.logHtml(dbId,"cache_size =",cacheSize); - }); - }else{ - const capi = this.sqlite3.capi, wasm = this.sqlite3.wasm; - const stack = wasm.scopedAllocPush(); - let pDb = 0; - try{ - const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE; - const ppDb = wasm.scopedAllocPtr(); - const rc = capi.sqlite3_open_v2(d.filename, ppDb, oFlags, null); - pDb = wasm.peekPtr(ppDb) - if(rc) toss("sqlite3_open_v2() failed with code",rc); - capi.sqlite3_exec(pDb, "PRAGMA cache_size="+cacheSize, 0, 0, 0); - this.logHtml(dbId,"cache_size =",cacheSize); - }catch(e){ - if(pDb) capi.sqlite3_close_v2(pDb); - }finally{ - wasm.scopedAllocPop(stack); - } - d.handle = pDb; - d.clear = ()=>clearDbSqlite(d); - } - d.clear(); - this.logHtml("Opened db:",dbId,d.filename); - console.log("db =",d); - return d; - }, - - run: function(sqlite3){ - delete this.run; - this.sqlite3 = sqlite3; - const capi = sqlite3.capi, wasm = sqlite3.wasm; - this.logHtml("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid()); - this.logHtml("WASM heap size =",wasm.heap8().length); - this.loadSqlList(); - if(capi.sqlite3_wasmfs_opfs_dir()){ - E('#warn-opfs').classList.remove('hidden'); - }else{ - E('#warn-opfs').remove(); - E('option[value=wasmfs-opfs]').disabled = true; - } - if('function' === typeof self.openDatabase){ - E('#warn-websql').classList.remove('hidden'); - }else{ - E('option[value=websql]').disabled = true; - E('#warn-websql').remove(); - } - const who = this; - if(this.e.cbReverseLog.checked){ - this.e.output.classList.add('reverse'); - } - this.e.cbReverseLog.addEventListener('change', function(){ - who.e.output.classList[this.checked ? 'add' : 'remove']('reverse'); - }, false); - 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(){ - who.clearStorage(true); - }, false); - this.e.btnExportMetrics.addEventListener('click', function(){ - who.logHtml2('warning',"Triggering download of metrics CSV. Check your downloads folder."); - who.downloadMetrics(); - //const m = who.metricsToArrays(); - //console.log("Metrics:",who.metrics, m); - }); - this.e.selImpl.addEventListener('change', function(){ - who.getSelectedDb(); - }); - 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))"); - who.clearStorage(); - App.metrics.runTimeMs = timeTotal; - who.logHtml("Total metrics:",JSON.stringify(App.metrics,undefined,' ')); - }, false); - }/*run()*/ - }/*App*/; - - self.sqlite3TestModule.initSqlite3().then(function(sqlite3_){ - sqlite3 = sqlite3_; - self.App = App /* only to facilitate dev console access */; - App.run(sqlite3); - }); -})(); diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index bdf59e35d5..3fa3af3ac3 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -103,7 +103,9 @@ struct BuildDef { */ const char *zDotWasm; const char *zCmppD; /* Extra -D... flags for c-pp */ - const char *zEmcc; /* Extra flags for emcc */ + const char *zEmcc; /* Full flags for emcc. Normally NULL for default. */ + const char *zEmccExtra; /* Extra flags for emcc */ + const char *zDeps; /* Extra deps */ const char *zEnv; /* emcc -sENVIRONMENT=... value */ /* ** Makefile code "ifeq (...)". If set, this build is enclosed in a @@ -152,6 +154,7 @@ typedef struct BuildDef BuildDef; E(vanilla) E(vanilla64) \ E(esm) E(esm64) \ E(bundler) E(bundler64) \ + E(speedtest1) \ E(node) E(node64) \ E(wasmfs) @@ -183,7 +186,9 @@ const BuildDefs oBuildDefs = { .zDotWasm = 0, .zCmppD = 0, .zEmcc = 0, + .zEmccExtra = 0, .zEnv = "web,worker", + .zDeps = 0, .zIfCond = 0, .flags = CP_ALL }, @@ -194,8 +199,10 @@ const BuildDefs oBuildDefs = { .zBaseName = "sqlite3-64bit", .zDotWasm = 0, .zCmppD = 0, - .zEmcc = "-sMEMORY64=1 -sWASM_BIGINT=1", + .zEmcc = 0, + .zEmccExtra = "-sMEMORY64=1 -sWASM_BIGINT=1", .zEnv = 0, + .zDeps = 0, .zIfCond = 0, .flags = CP_ALL | F_64BIT }, @@ -207,7 +214,9 @@ const BuildDefs oBuildDefs = { .zDotWasm = 0, .zCmppD = "-Dtarget=es6-module", .zEmcc = 0, + .zEmccExtra = 0, .zEnv = 0, + .zDeps = 0, .zIfCond = 0, .flags = CP_JS | F_ESM }, @@ -218,12 +227,41 @@ const BuildDefs oBuildDefs = { .zBaseName = "sqlite3-64bit", .zDotWasm = 0, .zCmppD = "-Dtarget=es6-module", - .zEmcc = "-sMEMORY64=1 -sWASM_BIGINT=1", + .zEmcc = 0, + .zEmccExtra = "-sMEMORY64=1 -sWASM_BIGINT=1", .zEnv = 0, + .zDeps = 0, .zIfCond = 0, .flags = CP_JS | F_ESM | F_64BIT }, + /* speedtest1, our primary benchmarking tool */ + .speedtest1 = { + .zEmo = "🛼", + .zBaseName = "speedtest1", + .zDotWasm = 0, + .zCmppD = 0, + .zEmcc = + "$(emcc.speedtest1)" + " $(emcc.speedtest1.common)" + " $(pre-post.speedtest1.flags)" + " $(cflags.common)" + " -DSQLITE_SPEEDTEST1_WASM" + " $(SQLITE_OPT)" + " -USQLITE_WASM_BARE_BONES" + " -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c)" + " $(speedtest1.exit-runtime0)" + " $(speedtest1.c.in)" + " -lm", + .zEmccExtra = 0, + .zEnv = 0, + .zDeps = + "$(speedtest1.c.in)" + " $(EXPORTED_FUNCTIONS.speedtest1)", + .zIfCond = 0, + .flags = CP_ALL + }, + /* ** Core bundler-friendly build. Untested and "not really" supported, ** but required by the downstream npm subproject. @@ -239,7 +277,9 @@ const BuildDefs oBuildDefs = { .zDotWasm = "sqlite3", .zCmppD = "$(c-pp.D.esm) -Dtarget=es6-bundler-friendly", .zEmcc = 0, + .zEmccExtra = 0, .zEnv = 0, + .zDeps = 0, .zIfCond = 0, .flags = CP_JS | F_BUNDLER_FRIENDLY | F_ESM //| F_NOT_IN_ALL @@ -251,8 +291,10 @@ const BuildDefs oBuildDefs = { .zBaseName = "sqlite3-bundler-friendlyu", .zDotWasm = "sqlite3-64bit", .zCmppD = "$(c-pp.D.bundler)", - .zEmcc = "-sMEMORY64=1", + .zEmcc = 0, + .zEmccExtra = "-sMEMORY64=1", .zEnv = 0, + .zDeps = 0, .zIfCond = 0, .flags = CP_JS | F_ESM | F_BUNDLER_FRIENDLY | F_64BIT | F_NOT_IN_ALL }, @@ -268,11 +310,13 @@ const BuildDefs oBuildDefs = { .zDotWasm = 0, .zCmppD = "-Dtarget=node $(c-pp.D.bundler)", .zEmcc = 0, + .zEmccExtra = 0, .zEnv = "node" /* Adding ",node" to the zEnv list for the other builds causes ** Emscripten to generate code which confuses node: it cannot ** reliably determine whether the build is for a browser or for ** node. */, + .zDeps = 0, .zIfCond = 0, .flags = CP_ALL | F_UNSUPPORTED | F_NODEJS }, @@ -284,7 +328,9 @@ const BuildDefs oBuildDefs = { .zDotWasm = 0, .zCmppD = "-Dtarget=node $(c-pp.D.bundler)", .zEmcc = 0, + .zEmccExtra = 0, .zEnv = "node", + .zDeps = 0, .zIfCond = 0, .flags = CP_ALL | F_UNSUPPORTED | F_NODEJS | F_64BIT }, @@ -295,8 +341,10 @@ const BuildDefs oBuildDefs = { .zBaseName = "sqlite3-wasmfs", .zDotWasm = 0, .zCmppD = "$(c-pp.D.bundler)", - .zEmcc = "-sEXPORT_ES6 -sUSE_ES6_IMPORT_META", + .zEmcc = 0, + .zEmccExtra = "-sEXPORT_ES6 -sUSE_ES6_IMPORT_META", .zEnv = 0, + .zDeps = 0, .zIfCond = "ifeq (1,$(HAVE_WASMFS))", .flags = CP_ALL | F_UNSUPPORTED | F_WASMFS } @@ -592,6 +640,7 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ zBuildName, zBuildName ); pf("dir.dout.%s ?= $(dir.dout)/%s\n", zBuildName, zBuildName); + pf("out.%s.base ?= $(dir.dout.%s)/%s\n", zBuildName, zBuildName, zBaseName); pf("out.%s.js ?= $(dir.dout.%s)/%s%s\n", @@ -600,19 +649,20 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ //"$(basename $@).wasm" zBuildName, zBuildName, zBaseName); - pf("dir.dout.%s ?= $(dir.dout)/%s\n", zBuildName, zBuildName); pf("out.%s.base ?= $(dir.dout.%s)/%s\n", zBuildName, zBuildName, zBaseName); - pf("out.%s.js ?= $(dir.dout.%s)/%s%s\n", - zBuildName, zBuildName, zBaseName, zJsExt); - pf("out.%s.wasm ?= $(dir.dout.%s)/%s.wasm\n", - //"$(basename $@).wasm" - zBuildName, zBuildName, zBaseName); + + if( pB->zDeps ){ + pf("deps.%s += %s\n", zBuildName, pB->zDeps); + } + pf("c-pp.D.%s ?= %s\n", zBuildName, pB->zCmppD ? pB->zCmppD : ""); pf("emcc.environment.%s ?= %s\n", zBuildName, pB->zEnv ? pB->zEnv : oBuildDefs.vanilla.zEnv); - pf("emcc.flags.%s ?= %s\n", zBuildName, pB->zEmcc ? pB->zEmcc : ""); + if( pB->zEmccExtra ){ + pf("emcc.flags.%s = %s\n", zBuildName, pB->zEmccExtra); + } emit_api_js(zBuildName, pB->zCmppD); if( pB->flags & F_64BIT ){ @@ -623,10 +673,10 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ { /* build it... */ pf(zBanner "$(out.%s.js): $(MAKEFILE_LIST) $(sqlite3-wasm.cfiles)" - " $(EXPORTED_FUNCTIONS.api)" + " $(EXPORTED_FUNCTIONS.api) $(deps.%s)" " $(bin.mkwb) $(pre-post.%s.deps)" "\n", - zBuildName, zBuildName); + zBuildName, zBuildName, zBuildName); emit_compile_start(zBuildName); @@ -634,7 +684,27 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ pf("\t@echo '$(logtag.%s) $(emo.fire)$(emo.fire)$(emo.fire): " "unsupported build. Use at your own risk.'\n", zBuildName); } - pf("\t$(b.cmd@)$(call b.do.emcc,%s)\n", zBuildName); + + /* emcc ... */ + { + pf("\t$(b.cmd@)$(bin.emcc) -o $@ "); + if( pB->zEmcc ){ + pf("%s $(emcc.flags.%s)\n", + pB->zEmcc, zBuildName); + }else{ + pf("$(emcc_opt_full) $(emcc.flags)" + " $(emcc.jsflags)" + " -sENVIRONMENT=$(emcc.environment.%s)" + " $(pre-post.%s.flags)" + " $(emcc.flags.%s)" + " $(cflags.common)" + " $(cflags.%s)" + " $(SQLITE_OPT)" + " $(cflags.wasm_extra_init) $(sqlite3-wasm.cfiles)\n", + zBuildName, zBuildName, zBuildName, zBuildName + ); + } + } { /* Post-compilation transformations and copying to $(dir.dout)... */ @@ -669,7 +739,7 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ /* ** $(bin.emcc) will write out $@ and will create a like-named ** .wasm file. The resulting .wasm and .js/.mjs files are - ** identical across all builds which have the same pB->zEmcc. + ** identical across all builds which have the same pB->zEmccExtra. ** ** We copy one or both of those files to $(dir.dout) (the top-most ** build target dir), but: that .wasm file name gets hard-coded @@ -831,6 +901,7 @@ static void mk_fiddle(void){ } } +#if 0 static void mk_speedtest1(void){ char const *zBuildName = "speedtest1"; pf(zBanner "# Begin build %s\n", zBuildName); @@ -867,30 +938,53 @@ static void mk_speedtest1(void){ "$(c-pp.D.sqlite3-bundler-friendly) -Dwasmfs", "speetest1-wasmfs.wasm"); #endif - } +#endif -int main(void){ +int main(int argc, char const ** argv){ int rc = 0; const BuildDef *pB; pf("# What follows was GENERATED by %s. Edit at your own risk.\n", __FILE__); - mk_prologue(); + + if(argc>1){ + /* + ** Only emit the rules for the given list of builds, sans + ** prologue. Only for debugging, not makefile generation. + */ + for( int i = 1; i < argc; ++i ){ + char const * const zArg = argv[i]; +#define E(N) if(0==strcmp(#N, zArg)) {mk_lib_mode(# N, &oBuildDefs.N);} else /**/ + BuildDefs_map(E) { + fprintf(stderr,"Unkown build name: %s\n", zArg); + rc = 1; + break; + } +#undef E + } + }else{ + /* + ** Emit the whole shebang... + */ + mk_prologue(); #define E(N) mk_lib_mode(# N, &oBuildDefs.N); - BuildDefs_map(E) + BuildDefs_map(E) #undef E - pf(zBanner - "$(dir.dout)/sqlite3.js: $(out.vanilla.js)\n" - "$(dir.dout)/sqlite3.mjs: $(out.esm.js)\n" - "$(dir.dout)/sqlite3.wasm: $(out.vanilla.wasm)\n" - "$(dir.dout)/sqlite3-64bit.js: $(out.vanilla64.js)\n" - "$(dir.dout)/sqlite3-64bit.mjs: $(out.esm64.js)\n" - "$(dir.dout)/sqlite3-64bit.wasm: $(out.vanilla64.wasm)\n" - "b-vanilla: $(dir.dout)/sqlite3.wasm\n" - "b-vanilla64: $(dir.dout)/sqlite3-64bit.wasm\n" - "b-esm: $(dir.dout)/sqlite3.mjs\n" - "b-esm64: $(dir.dout)/sqlite3-64bit.mjs\n" - ); - mk_fiddle(); - mk_speedtest1(); +#if 0 + pf(zBanner + "$(dir.dout)/sqlite3.js: $(out.vanilla.js)\n" + "$(dir.dout)/sqlite3.mjs: $(out.esm.js)\n" + "$(dir.dout)/sqlite3.wasm: $(out.vanilla.wasm)\n" + "$(dir.dout)/sqlite3-64bit.js: $(out.vanilla64.js)\n" + "$(dir.dout)/sqlite3-64bit.mjs: $(out.esm64.js)\n" + "$(dir.dout)/sqlite3-64bit.wasm: $(out.vanilla64.wasm)\n" + "b-vanilla: $(dir.dout)/sqlite3.wasm\n" + "b-vanilla64: $(dir.dout)/sqlite3-64bit.wasm\n" + "b-esm: $(dir.dout)/sqlite3.mjs\n" + "b-esm64: $(dir.dout)/sqlite3-64bit.mjs\n" + ); +#endif + mk_fiddle(); + //mk_speedtest1(); + } return rc; } diff --git a/manifest b/manifest index a568a30b1e..204db3e1fc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Wasm\sbuild\sdeps\sfixes. -D 2025-09-25T00:53:30.968 +C Consolidate\sthe\sspeedtest1\swasm\sbuild\sinto\sthe\snew\smkwasmbuilds.c\smodel.\sRemove\sthe\slong-unused\sbatch-runner\sJS\stools. +D 2025-09-25T02:02:48.595 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -578,7 +578,7 @@ F ext/session/sqlite3session.c 9cd47bfefb23c114b7a5d9ee5822d941398902f30516bf0dd F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c -F ext/wasm/GNUmakefile 3e4798dd38252e361b4baab2cba60ef329621a3d1955db0c53b004f3a37e8630 +F ext/wasm/GNUmakefile a5abc4ad90d9426e80a24778fedfb5947d827e22f53ae4cff99ccc8e52bcfdd7 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -610,10 +610,6 @@ F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72 F ext/wasm/api/sqlite3-wasm.c ff2dc011e17b06186b8b35e408626d7ace69a362b92c197a34d78bef25c7105a F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js 8fb6adfbae6270344f43f2652e63780df3f86521755bde8f92cf6b809ba7891d F ext/wasm/api/sqlite3-worker1.c-pp.js 69483df1df2d0988e708390f7b1feda769c16e9e9efd4683557f8e7197099cc0 -F ext/wasm/batch-runner-sahpool.html e9a38fdeb36a13eac7b50241dfe7ae066fe3f51f5c0b0151e7baee5fce0d07a7 -F ext/wasm/batch-runner-sahpool.js 54a3ac228e6c4703fe72fb65c897e19156263a51fe9b7e21d2834a45e876aabd -F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 -F ext/wasm/batch-runner.js 05ec254f5dbfe605146d9640b3db17d6ef8c3fbef6aa8396051ca72bb5884e3f F ext/wasm/c-pp.c 7692739ac435120c37b9de993f152c90e5dbf6a340ca6331de81d7b8b06b5307 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15 @@ -639,7 +635,7 @@ F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf1 F ext/wasm/index.html 1b329fb63e057c02a17ce178308d6b06aac62d92af7dd6d821fb0e183e0f1557 F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f -F ext/wasm/mkwasmbuilds.c 238cc9a9888dec4a9b48e9b608982cc5b7f4b307438d9266e0d4fcca939d697d +F ext/wasm/mkwasmbuilds.c 29e55190b6bdb2b9a52966e34144c3af3948331fd65a713910c9c7231d75f4b6 F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -2175,8 +2171,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 18beeb26bfa48f806866e0e330024535adabcf668071abc4b6251eb39de2701d -R b0e1a74c5137f4633645ae07790f221a +P fd0c649047f4e444ea682138a3555a973839627150e1124bb9d9ced17880a9e5 +R 4644e40acad7ec2826869dd780c99c6c U stephan -Z 436e3963d5b7b3aa761dea055937d61e +Z 003460e9650f2a4bf650b04d84b0f4a7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 51e6980ca1..e7a8a287d5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fd0c649047f4e444ea682138a3555a973839627150e1124bb9d9ced17880a9e5 +980c033c05bf37c0e8f5e82486ee99ba1294cc9c9e2087aaf83b64e5d0118b5f -- 2.47.3