]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Consolidate the speedtest1 wasm build into the new mkwasmbuilds.c model. Remove the...
authorstephan <stephan@noemail.net>
Thu, 25 Sep 2025 02:02:48 +0000 (02:02 +0000)
committerstephan <stephan@noemail.net>
Thu, 25 Sep 2025 02:02:48 +0000 (02:02 +0000)
FossilOrigin-Name: 980c033c05bf37c0e8f5e82486ee99ba1294cc9c9e2087aaf83b64e5d0118b5f

ext/wasm/GNUmakefile
ext/wasm/batch-runner-sahpool.html [deleted file]
ext/wasm/batch-runner-sahpool.js [deleted file]
ext/wasm/batch-runner.html [deleted file]
ext/wasm/batch-runner.js [deleted file]
ext/wasm/mkwasmbuilds.c
manifest
manifest.uuid

index e536ebeba88500cba7e0d7b1ccfcb5a4b5f13787..4da0627719eea23e30458e30b5d89f6d5b61de53 100644 (file)
@@ -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 (file)
index ad7e7b5..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<!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/testing.css"/>
-    <title>sqlite3-api batch SQL runner for the SAHPool VFS</title>
-  </head>
-  <body>
-    <header id='titlebar'><span>sqlite3-api batch SQL runner for the SAHPool VFS</span></header>
-    <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' class='reverse'></div>
-    <script>
-      (function(){
-        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 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);
-
-        const w = new Worker('batch-runner-sahpool.js?sqlite3.dir=jswasm');
-        w.onmessage = function(msg){
-          msg = msg.data;
-          switch(msg.type){
-            case 'stdout': log(...msg.data); break;
-            case 'warn': logWarn(...msg.data); break;
-            case 'error': logErr(...msg.data); break;
-            default:
-              logErr("Unhandled worker message type:",msg);
-              break;
-          }
-        };
-      })();
-    </script>
-    <style>
-      #test-output {
-          white-space: break-spaces;
-          overflow: auto;
-      }
-    </style>
-  </body>
-</html>
diff --git a/ext/wasm/batch-runner-sahpool.js b/ext/wasm/batch-runner-sahpool.js
deleted file mode 100644 (file)
index dfa5044..0000000
+++ /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 (file)
index 5258f95..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-<!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>sqlite3-api batch SQL runner</title>
-  </head>
-  <body>
-    <header id='titlebar'><span>sqlite3-api batch SQL runner</span></header>
-    <!-- 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 -->
-    <p>
-      This page is for batch-running extracts from the output
-      of <tt>speedtest1 --script</tt>, as well as other standalone SQL
-      scripts.
-    </p>
-    <p id='warn-list' class='warning'>ACHTUNG: this file requires a generated input list
-      file. Run "make batch" from this directory to generate it.
-    </p>
-    <p id='warn-opfs' class='warning hidden'>WARNING: if the WASMFS/OPFS layer crashes, this page may
-      become completely unresponsive and need to be closed and reloaded to recover.
-    </p>
-    <p id='warn-websql' class='warning hidden'>WARNING: WebSQL's limited API requires that
-      this app split up SQL batches into separate statements for execution. That will
-      only work so long as semicolon characters are <em>only</em> used to terminate
-      SQL statements, and not used within string literals or the like.
-    </p>
-    <hr>
-    <fieldset id='toolbar'>
-      <div>
-        <select class='disable-during-eval' id='sql-select'>
-          <option disabled selected>Populated via script code</option>
-        </select>
-        <button class='disable-during-eval' id='sql-run'>Run selected SQL</button>
-        <button class='disable-during-eval' id='sql-run-next'>Run next...</button>
-        <button class='disable-during-eval' id='sql-run-remaining'>Run all remaining...</button>
-        <button class='disable-during-eval' id='export-metrics' disabled>Export metrics (WIP)<br>(broken by refactoring)</button>
-        <button class='disable-during-eval' id='db-reset'>Reset db</button>
-        <button id='output-clear'>Clear output</button>
-        <span class='input-wrapper flex-col'>
-          <label for='select-impl'>Storage impl:</label>
-          <select id='select-impl'>
-            <option value='virtualfs'>Virtual filesystem</option>
-            <option value='memdb'>:memory:</option>
-            <option value='wasmfs-opfs'>WASMFS OPFS</option>
-            <option value='websql'>WebSQL</option>
-          </select>
-        </span>
-      </fieldset>
-    </div>
-    <hr>
-      <span class='input-wrapper'>
-        <input type='checkbox' class='disable-during-eval' id='cb-reverse-log-order' checked></input>
-        <label for='cb-reverse-log-order'>Reverse log order (newest first)</label>
-      </span>
-    <div id='test-output'></div>
-    <script src="jswasm/sqlite3.js"></script>
-    <script src="common/SqliteTestUtil.js"></script>
-    <script src="batch-runner.js"></script>
-    <style>
-      .flex-col {
-          display: flex;
-          flex-direction: column;
-      }
-      #toolbar > div {
-          display: flex;
-          flex-direction: row;
-          flex-wrap: wrap;
-      }
-      #toolbar > div > * {
-          margin: 0.25em;
-      }
-    </style>
-  </body>
-</html>
diff --git a/ext/wasm/batch-runner.js b/ext/wasm/batch-runner.js
deleted file mode 100644 (file)
index e7a322b..0000000
+++ /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);
-  });
-})();
index bdf59e35d521fe4a2be29f6a40926600231d4cab..3fa3af3ac35cbd373c484768fdc3d5d6086b3ff8 100644 (file)
@@ -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;
 }
index a568a30b1ef9e635f2f615d71cb97e4db52e1c6d..204db3e1fc50c3f874a3833459616bc09defff87 100644 (file)
--- 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.
index 51e6980ca1accda8f1c3160adc3ded33abbf2af1..e7a8a287d5005626189ba4f89267c46e08ec66f2 100644 (file)
@@ -1 +1 @@
-fd0c649047f4e444ea682138a3555a973839627150e1124bb9d9ced17880a9e5
+980c033c05bf37c0e8f5e82486ee99ba1294cc9c9e2087aaf83b64e5d0118b5f