Mercurial > hg > piper-vamp-js
changeset 33:e9a0f66ee81c
Quick in-browser performance test
author | Chris Cannam |
---|---|
date | Sat, 24 Sep 2016 16:26:04 +0100 |
parents | 30028b3c95e4 |
children | 0eafc96a039c |
files | perf-test.html perf-test.js |
diffstat | 2 files changed, 169 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perf-test.html Sat Sep 24 16:26:04 2016 +0100 @@ -0,0 +1,21 @@ +<html> + <head> + <meta charset="UTF-8"> + <title>VamPipe Adapter Test</title> + + <style type="text/css"> + body { margin: 5%; } + table, td, th { border: 0.1em solid #e0e0e0; border-collapse: collapse } + td, th { padding: 0.5em } + </style> + + <script src="VampExamplePlugins.js"></script> + <script src="perf-test.js"></script> + </head> + <body> + <h3>VamPipe Adapter Test</h3> + + <p id="test-result"></p> + + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perf-test.js Sat Sep 24 16:26:04 2016 +0100 @@ -0,0 +1,148 @@ +"use strict"; + +var exampleModule = VampExamplePluginsModule(); + +// It is possible to declare both parameters and return values as +// "string", in which case Emscripten will take care of +// conversions. But it's not clear how one would manage memory for +// newly-constructed returned C strings -- the returned pointer from +// vampipeRequestJson would appear (?) to be thrown away by the +// Emscripten string converter if we declare it as returning a string, +// so we have no opportunity to pass it to vampipeFreeJson, which +// suggests this would leak memory if the string isn't static. Not +// wholly sure though. Anyway, passing and returning pointers (as +// numbers) means we can manage the Emscripten heap memory however we +// want in our request wrapper function below. + +var vampipeRequestJson = exampleModule.cwrap( + 'vampipeRequestJson', 'number', ['number'] +); + +var vampipeProcessRaw = exampleModule.cwrap( + "vampipeProcessRaw", "number", ["number", "number", "number", "number"] +); + +var vampipeFreeJson = exampleModule.cwrap( + 'vampipeFreeJson', 'void', ['number'] +); + +function note(blah) { + document.getElementById("test-result").innerHTML += blah + "<br>"; +} + +function comment(blah) { + note("<br><i>" + blah + "</i>"); +} + +function processRaw(request) { + + const nChannels = request.processInput.inputBuffers.length; + const nFrames = request.processInput.inputBuffers[0].values.length; + + const buffersPtr = exampleModule._malloc(nChannels * 4); + const buffers = new Uint32Array( + exampleModule.HEAPU8.buffer, buffersPtr, nChannels); + + for (let i = 0; i < nChannels; ++i) { + const framesPtr = exampleModule._malloc(nFrames * 4); + const frames = new Float32Array( + exampleModule.HEAPU8.buffer, framesPtr, nFrames); + frames.set(request.processInput.inputBuffers[i].values); + buffers[i] = framesPtr; + } + + const responseJson = vampipeProcessRaw( + request.pluginHandle, + buffersPtr, + request.processInput.timestamp.s, + request.processInput.timestamp.n); + + for (let i = 0; i < nChannels; ++i) { + exampleModule._free(buffers[i]); + } + exampleModule._free(buffersPtr); + + const response = JSON.parse( + exampleModule.Pointer_stringify(responseJson)); + + vampipeFreeJson(responseJson); + + return response; +} + +function request(jsonStr) { + note("Request JSON = " + jsonStr); + var m = exampleModule; + // Inspection reveals that intArrayFromString converts the string + // from utf16 to utf8, which is what we want (though the docs + // don't mention this). Note the *Cstr values are Emscripten heap + // pointers + var inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL); + var outCstr = vampipeRequestJson(inCstr); + m._free(inCstr); + var result = m.Pointer_stringify(outCstr); + vampipeFreeJson(outCstr); + note("Returned JSON = " + result); + return result; +} + +function test() { + + comment("Loading zero crossings plugin..."); + let result = request('{"type":"load","content": {"pluginKey":"vamp-example-plugins:zerocrossing","inputSampleRate":44100,"adapterFlags":["AdaptAllSafe"]}}'); + + const blockSize = 1024; + + result = request('{"type":"configure","content":{"pluginHandle":1,"configuration":{"blockSize": ' + blockSize + ', "channelCount": 1, "stepSize": ' + blockSize + '}}}'); + + const nblocks = 1000; + + let processInputBuffers = [new Float32Array( + Array.from(Array(blockSize).keys(), n => n / blockSize)) + ]; + + comment("Now processing " + nblocks + " blocks of 1024 samples each..."); + + let start = (new Date()).getTime(); + comment("Start at " + start); + + for (let i = 0; i < nblocks; ++i) { + let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it + result = processRaw({ + "pluginHandle": 1, + "processInput": { + "timestamp": ts, + "inputBuffers": processInputBuffers + } + }); + } + + let finish = (new Date()).getTime(); + comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); + + comment("Again..."); + + start = (new Date()).getTime(); + comment("Start at " + start); + + for (let i = 0; i < nblocks; ++i) { + let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it + result = processRaw({ + "pluginHandle": 1, + "processInput": { + "timestamp": ts, + "inputBuffers": processInputBuffers + } + }); + } + + finish = (new Date()).getTime(); + comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); + + comment("Cleaning up the plugin and getting any remaining features..."); + result = request('{"type":"finish","content":{"pluginHandle":1}}'); +} + +window.onload = function() { + test(); +}