aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-api-opfs.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-09-19 17:09:09 +0000
committerstephan <stephan@noemail.net>2022-09-19 17:09:09 +0000
commitf815011a085e86117da3e28f8281fb13cf1bcdf9 (patch)
treea408bdfa2cb7c04f6ddd7bb1571e3bed92aa8b39 /ext/wasm/api/sqlite3-api-opfs.js
parent61418d5a679f11bbf3517431777c14b30252bd75 (diff)
downloadsqlite-f815011a085e86117da3e28f8281fb13cf1bcdf9.tar.gz
sqlite-f815011a085e86117da3e28f8281fb13cf1bcdf9.zip
Cut the speedtest1 runtime of the OPFS VFS proxy by approximately 3/4ths via xRead/xWrite buffer-copying optimizations. Still slower than the WASMFS impl by approx. 1/5th.
FossilOrigin-Name: fb7f287310d74a3e236125ae9c49b859f9263c29ae85161c1bcf9dd0778d8a51
Diffstat (limited to 'ext/wasm/api/sqlite3-api-opfs.js')
-rw-r--r--ext/wasm/api/sqlite3-api-opfs.js94
1 files changed, 81 insertions, 13 deletions
diff --git a/ext/wasm/api/sqlite3-api-opfs.js b/ext/wasm/api/sqlite3-api-opfs.js
index 62aad0c4b..b7e6887f6 100644
--- a/ext/wasm/api/sqlite3-api-opfs.js
+++ b/ext/wasm/api/sqlite3-api-opfs.js
@@ -134,6 +134,34 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
by the Promise setup and, on success, installed as sqlite3.opfs.
*/
const opfsUtil = Object.create(null);
+ /**
+ Not part of the public API. Solely for internal/development
+ use.
+ */
+ opfsUtil.metrics = {
+ dump: function(){
+ let k, n = 0, t = 0;
+ for(k in metrics){
+ const m = metrics[k];
+ n += m.count;
+ t += m.time;
+ m.avgTime = (m.count && m.time) ? (m.time / m.count) : 0;
+ m.avgWait = (m.count && m.wait) ? (m.wait / m.count) : 0;
+ }
+ console.log("metrics for",self.location.href,":",metrics,
+ "\nTotal of",n,"op(s) for",t,"ms");
+ },
+ reset: function(){
+ let k;
+ const r = (m)=>(m.count = m.time = m.wait = 0);
+ for(k in state.opIds){
+ r(metrics[k] = Object.create(null));
+ }
+ [ // timed routines which are not in state.opIds
+ 'xFileControl'
+ ].forEach((k)=>r(metrics[k] = Object.create(null)));
+ }
+ }/*metrics*/;
/**
State which we send to the async-api Worker or share with it.
@@ -165,6 +193,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
state.fbInt64Offset =
state.fileBufferSize - 8 /*spot in fileHandle.sab to store an int64 result */;
state.opIds = Object.create(null);
+ const metrics = Object.create(null);
{
let i = 0;
state.opIds.xAccess = i++;
@@ -180,6 +209,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
state.opIds.xWrite = i++;
state.opIds.mkdir = i++;
state.opSAB = new SharedArrayBuffer(i * 4/*sizeof int32*/);
+ opfsUtil.metrics.reset();
}
state.sq3Codes = Object.create(null);
@@ -207,9 +237,11 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
given operation's signature in the async API counterpart.
*/
const opRun = (op,args)=>{
+ const t = performance.now();
Atomics.store(state.opSABView, state.opIds[op], -1);
wMsg(op, args);
Atomics.wait(state.opSABView, state.opIds[op], -1);
+ metrics[op].wait += performance.now() - t;
return Atomics.load(state.opSABView, state.opIds[op]);
};
@@ -338,7 +370,20 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
tgt.ondispose.__removeFuncList.push(memKey, pFunc);
return (n,f)=>callee(tgt, n, f);
}/*installMethod*/;
-
+
+ const opTimer = Object.create(null);
+ opTimer.op = undefined;
+ opTimer.start = undefined;
+ const mTimeStart = (op)=>{
+ opTimer.start = performance.now();
+ opTimer.op = op;
+ //metrics[op] || toss("Maintenance required: missing metrics for",op);
+ ++metrics[op].count;
+ };
+ const mTimeEnd = ()=>(
+ metrics[opTimer.op].time += performance.now() - opTimer.start
+ );
+
/**
Impls for the sqlite3_io_methods methods. Maintenance reminder:
members are in alphabetical order to simplify finding them.
@@ -351,6 +396,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
return 0;
},
xClose: function(pFile){
+ mTimeStart('xClose');
let rc = 0;
const f = __openFiles[pFile];
if(f){
@@ -358,22 +404,29 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
rc = opRun('xClose', pFile);
if(f.sq3File) f.sq3File.dispose();
}
+ mTimeEnd();
return rc;
},
xDeviceCharacteristics: function(pFile){
//debug("xDeviceCharacteristics(",pFile,")");
return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
},
- xFileControl: function(pFile,op,pArg){
- //debug("xFileControl(",arguments,") is a no-op");
+ xFileControl: function(pFile, opId, pArg){
+ mTimeStart('xFileControl');
+ if(capi.SQLITE_FCNTL_SYNC===opId){
+ return opRun('xSync', {fid:pFile, flags:0});
+ }
+ mTimeEnd();
return capi.SQLITE_NOTFOUND;
},
xFileSize: function(pFile,pSz64){
+ mTimeStart('xFileSize');
const rc = opRun('xFileSize', pFile);
if(!isWorkerErrCode(rc)){
const f = __openFiles[pFile];
- wasm.setMemValue(pSz64, f.sabViewFileSize.getBigInt64(0) ,'i64');
+ wasm.setMemValue(pSz64, f.sabViewFileSize.getBigInt64(0,true) ,'i64');
}
+ mTimeEnd();
return rc;
},
xLock: function(pFile,lockType){
@@ -383,26 +436,31 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
},
xRead: function(pFile,pDest,n,offset){
/* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */
+ mTimeStart('xRead');
const f = __openFiles[pFile];
let rc;
try {
// FIXME(?): block until we finish copying the xRead result buffer. How?
rc = opRun('xRead',{fid:pFile, n, offset});
if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){
- let i = 0;
- for(; i < n; ++i) wasm.setMemValue(pDest + i, f.sabView[i]);
+ // set() seems to be the fastest way to copy this...
+ wasm.heap8u().set(f.sabView.subarray(0, n), pDest);
}
}catch(e){
error("xRead(",arguments,") failed:",e,f);
rc = capi.SQLITE_IOERR_READ;
}
+ mTimeEnd();
return rc;
},
xSync: function(pFile,flags){
- return opRun('xSync', {fid:pFile, flags});
+ return 0; // impl'd in xFileControl(). opRun('xSync', {fid:pFile, flags});
},
xTruncate: function(pFile,sz64){
- return opRun('xTruncate', {fid:pFile, size: sz64});
+ mTimeStart('xTruncate');
+ const rc = opRun('xTruncate', {fid:pFile, size: sz64});
+ mTimeEnd();
+ return rc;
},
xUnlock: function(pFile,lockType){
//2022-09: OPFS handles lock when opened
@@ -411,16 +469,19 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
},
xWrite: function(pFile,pSrc,n,offset){
/* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */
+ mTimeStart('xWrite');
const f = __openFiles[pFile];
+ let rc;
try {
- let i = 0;
// FIXME(?): block from here until we finish the xWrite. How?
- for(; i < n; ++i) f.sabView[i] = wasm.getMemValue(pSrc+i);
- return opRun('xWrite',{fid:pFile, n, offset});
+ f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc+n));
+ rc = opRun('xWrite',{fid:pFile, n, offset});
}catch(e){
error("xWrite(",arguments,") failed:",e,f);
- return capi.SQLITE_IOERR_WRITE;
+ rc = capi.SQLITE_IOERR_WRITE;
}
+ mTimeEnd();
+ return rc;
}
}/*ioSyncWrappers*/;
@@ -430,8 +491,10 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
*/
const vfsSyncWrappers = {
xAccess: function(pVfs,zName,flags,pOut){
+ mTimeStart('xAccess');
const rc = opRun('xAccess', wasm.cstringToJs(zName));
wasm.setMemValue(pOut, rc ? 0 : 1, 'i32');
+ mTimeEnd();
return 0;
},
xCurrentTime: function(pVfs,pOut){
@@ -448,9 +511,11 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
return 0;
},
xDelete: function(pVfs, zName, doSyncDir){
+ mTimeStart('xDelete');
opRun('xDelete', {filename: wasm.cstringToJs(zName), syncDir: doSyncDir});
/* We're ignoring errors because we cannot yet differentiate
between harmless and non-harmless failures. */
+ mTimeEnd();
return 0;
},
xFullPathname: function(pVfs,zName,nOut,pOut){
@@ -469,6 +534,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
},
//xSleep is optionally defined below
xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
+ mTimeStart('xOpen');
if(!f._){
f._ = {
fileTypes: {
@@ -518,6 +584,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
args.sq3File.$pMethods = opfsIoMethods.pointer;
args.ba = new Uint8Array(args.sab);
}
+ mTimeEnd();
return rc;
}/*xOpen()*/
}/*vfsSyncWrappers*/;
@@ -600,7 +667,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
};
opfsUtil.OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
}
-
+
/**
Potential TODOs:
@@ -670,6 +737,7 @@ sqlite3.installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri)
}
}/*sanityCheck()*/;
+
W.onmessage = function({data}){
//log("Worker.onmessage:",data);
switch(data.type){