batch-runner.js: add rudimentary metrics export to CSV. Add a toggle to reverse the log output mode (in normal order or most recent first).

FossilOrigin-Name: b26e2bc05537a1f451db1bdd36a824d71c3ea25a130b6285f31ff9799d65fa7a
This commit is contained in:
stephan 2022-08-30 17:57:50 +00:00
parent ffc0cbb024
commit 53f635df55
5 changed files with 141 additions and 17 deletions

View File

@ -62,11 +62,14 @@ $(dir.top)/sqlite3.c:
emcc_opt ?= -O0
.PHONY: release
release:
$(MAKE) 'emcc_opt=-Os -g3'
$(MAKE) 'emcc_opt=-Os -g3 -flto'
# ^^^^^ target-specific vars, e.g.:
# release: emcc_opt=...
# apparently only work for file targets, not PHONY targets?
#
# ^^^ -flto improves runtime speed at -O0 considerably but doubles
# build time.
#
# ^^^^ -O3, -Oz, -Os minify symbol names and there appears to be no
# way around that except to use -g3, but -g3 causes the binary file
# size to absolutely explode (approx. 5x larger). This minification
@ -284,6 +287,7 @@ endif
CLEAN_FILES += $(sqlite3.js) $(sqlite3.wasm)
all: $(sqlite3.js)
wasm: $(sqlite3.js)
# End main Emscripten-based module build
########################################################################

View File

@ -42,11 +42,16 @@
<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'>Export metrics (WIP)</button>
<button class='disable-during-eval' id='db-reset'>Reset db</button>
<button id='output-clear'>Clear output</button>
<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</label>
</span>
</div>
<hr>
<div>(Log output is in reverse order, newest first!)</div>
<div id='reverse-log-notice' class='hidden'>(Log output is in reverse order, newest first!)</div>
<div id='test-output'></div>
<script src="sqlite3.js"></script>
@ -59,13 +64,25 @@
flex-wrap: wrap;
}
.warning { color: firebrick; }
.input-wrapper {
white-space: nowrap;
}
#test-output {
border: 1px inset;
padding: 0.25em;
/*max-height: 30em;*/
overflow: auto;
white-space: break-spaces;
display: flex; flex-direction: column-reverse;
display: flex; flex-direction: column;
}
#test-output.reverse {
flex-direction: column-reverse;
}
.hidden {
position: absolute !important;
opacity: 0 !important;
pointer-events: none !important;
display: none !important;
}
</style>
</body>

View File

@ -26,10 +26,22 @@
btnRun: document.querySelector('#sql-run'),
btnRunNext: document.querySelector('#sql-run-next'),
btnRunRemaining: document.querySelector('#sql-run-remaining'),
btnExportMetrics: document.querySelector('#export-metrics'),
btnClear: document.querySelector('#output-clear'),
btnReset: document.querySelector('#db-reset')
btnReset: document.querySelector('#db-reset'),
cbReverseLog: document.querySelector('#cb-reverse-log-order')
},
cache:{},
metrics:{
/**
Map of sql-file to timing metrics. We currently only store
the most recent run of each file, but we really should store
all runs so that we can average out certain values which vary
significantly across runs. e.g. a mandelbrot-generating query
will have a wide range of runtimes when run 10 times in a
row.
*/
},
log: console.log.bind(console),
warn: console.warn.bind(console),
cls: function(){this.e.output.innerHTML = ''},
@ -63,8 +75,11 @@
const oFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
const ppDb = wasm.scopedAllocPtr();
const rc = capi.sqlite3_open_v2(fn, ppDb, oFlags, null);
if(rc) toss("sqlite3_open_v2() failed with code",rc);
pDb = wasm.getPtrValue(ppDb)
if(rc){
if(pDb) capi.sqlite3_close_v2(pDb);
toss("sqlite3_open_v2() failed with code",rc);
}
}finally{
wasm.scopedAllocPop(stack);
}
@ -84,6 +99,12 @@
}
},
/**
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 = '';
@ -156,7 +177,62 @@
document.querySelectorAll('.disable-during-eval').forEach((e)=>e.disabled = disable);
},
/** Fetch ./fn and eval it as an SQL blob. */
/**
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.metrics).sort().forEach((k)=>{
const m = this.metrics[k];
delete m.evalFileStart;
delete m.evalFileEnd;
const mk = Object.keys(m).sort();
if(!rc.length){
rc.push(['file', ...mk]);
}
const row = [k.split('/').pop()/*remove dir prefix from filename*/];
rc.push(row);
mk.forEach((kk)=>row.push(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-metrics-'+((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);
const banner = "========================================";
@ -165,9 +241,11 @@
const capi = this.sqlite3.capi, wasm = capi.wasm;
let pStmt = 0, pSqlBegin;
const stack = wasm.scopedAllocPush();
const metrics = Object.create(null);
const metrics = this.metrics[fn] = 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 ["+fn+"]: error cleanup is pending.");
@ -180,11 +258,16 @@
let t;
let sqlByteLen = sql.byteLength;
const [ppStmt, pzTail] = wasm.scopedAllocPtr(2);
t = performance.now();
pSqlBegin = wasm.alloc( 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.setMemValue(pSql + sqlByteLen, 0);
metrics.strcpy = performance.now() - t;
let breaker = 0;
while(pSql && wasm.getMemValue(pSql,'i8')){
wasm.setPtrValue(ppStmt, 0);
@ -261,6 +344,20 @@
}
this.openDb(dbFile, !!pDir);
const who = this;
const eReverseLogNotice = document.querySelector('#reverse-log-notice');
if(this.e.cbReverseLog.checked){
eReverseLogNotice.classList.remove('hidden');
this.e.output.classList.add('reverse');
}
this.e.cbReverseLog.addEventListener('change', function(){
if(this.checked){
who.e.output.classList.add('reverse');
eReverseLogNotice.classList.remove('hidden');
}else{
who.e.output.classList.remove('reverse');
eReverseLogNotice.classList.add('hidden');
}
}, false);
this.e.btnClear.addEventListener('click', ()=>this.cls(), false);
this.e.btnRun.addEventListener('click', function(){
if(!who.e.selSql.value) return;
@ -278,6 +375,12 @@
who.openDb(fn,true);
}
}, false);
this.e.btnExportMetrics.addEventListener('click', function(){
who.logHtml2('warning',"Metrics export is a Work in Progress. See output in dev console.");
who.downloadMetrics();
const m = who.metricsToArrays();
console.log("Metrics:",who.metrics, m);
});
this.e.btnRunRemaining.addEventListener('click', async function(){
let v = who.e.selSql.value;
const timeStart = performance.now();

View File

@ -1,5 +1,5 @@
C batch-runner.js:\sre-enable\sunlink-before-run\sso\sthat\sOPFS\sspeedtest1\sbatch\scan\swork.
D 2022-08-30T10:26:33.223
C batch-runner.js:\sadd\srudimentary\smetrics\sexport\sto\sCSV.\sAdd\sa\stoggle\sto\sreverse\sthe\slog\soutput\smode\s(in\snormal\sorder\sor\smost\srecent\sfirst).
D 2022-08-30T17:57:50.778
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -474,7 +474,7 @@ F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
F ext/wasm/EXPORTED_FUNCTIONS.fiddle db7a4602f043cf4a5e4135be3609a487f9f1c83f05778bfbdf93766be4541b96
F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle a004bd5eeeda6d3b28d16779b7f1a80305bfe009dfc7f0721b042967f0d39d02
F ext/wasm/GNUmakefile b5d1e285ed9814646e1fb12a27b7507aea2d7208ef76e486e1471c8aabac5226
F ext/wasm/GNUmakefile fd1ba419c38d79f742849cc96a1f1e1dd63821e6173bc5727f0a5439f04b4131
F ext/wasm/README.md e1ee1e7c321c6a250bf78a84ca6f5882890a237a450ba5a0649c7a8399194c52
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 77ef4bcf37e362b9ad61f9c175dfc0f1b3e571563fb311b96581cf422ee6a8ec
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
@ -489,8 +489,8 @@ F ext/wasm/api/sqlite3-api-prologue.js 2d5c5d3355f55eefe51922cec5bfedbec0f8300db
F ext/wasm/api/sqlite3-api-worker1.js 73579555563b789785ae83724014eaf31811073aad9be6596c8336ffb51edd71
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 0d81282eaeff2a6e9fc5c28a388c5c5b45cf25a9393992fa511ac009b27df982
F ext/wasm/batch-runner.html e5c3edd4a6c9359f6d9e6c99cb5f87f09007d98fa1c705ed3efa370abcd4323e
F ext/wasm/batch-runner.js da471fb7b5c6c918cfe59adaebedc3af24a1268084d09d90143653c71b2493dd
F ext/wasm/batch-runner.html 439245594711981831f2775f1426fd20d73a9b1bbf53f2cbbfc1194fa069891c
F ext/wasm/batch-runner.js dfe194ff87dac20e641aeee7080b74a877ca4a24ea107d6a80ff8115b28b7f0b
F ext/wasm/common/SqliteTestUtil.js eb96275bed43fdb364b7d65bcded0ca5e22aaacff120d593d1385f852f486247
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 572cf1ffae0b6eb7ca63684d3392bf350217a07b90e7a896e4fa850700c989b0
@ -2013,8 +2013,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 06c106a7d23e4486dbed092757b7588688226ad35539ecc31378a8497f59d1ec
R 4e67c8f75eba175d0066f0954616ff1b
P ba08f7a7f12601aa580a8dc493b43cdd5ab65c87d5e4b3fd2f549343e45c2d2a
R cd46865d209bc499b87d03a53afeb5f7
U stephan
Z 9d799461f6bdad041adab908a7c4bd92
Z a638c92d95e9388486f91bc003769b2d
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
ba08f7a7f12601aa580a8dc493b43cdd5ab65c87d5e4b3fd2f549343e45c2d2a
b26e2bc05537a1f451db1bdd36a824d71c3ea25a130b6285f31ff9799d65fa7a