annotate perf-test.js @ 102:82f018d2dd0e

Quick in-browser performance test
author Chris Cannam <c.cannam@qmul.ac.uk>
date Sat, 24 Sep 2016 16:26:04 +0100
parents
children 3faa4e3eedac
rev   line source
c@102 1 "use strict";
c@102 2
c@102 3 var exampleModule = VampExamplePluginsModule();
c@102 4
c@102 5 // It is possible to declare both parameters and return values as
c@102 6 // "string", in which case Emscripten will take care of
c@102 7 // conversions. But it's not clear how one would manage memory for
c@102 8 // newly-constructed returned C strings -- the returned pointer from
c@102 9 // vampipeRequestJson would appear (?) to be thrown away by the
c@102 10 // Emscripten string converter if we declare it as returning a string,
c@102 11 // so we have no opportunity to pass it to vampipeFreeJson, which
c@102 12 // suggests this would leak memory if the string isn't static. Not
c@102 13 // wholly sure though. Anyway, passing and returning pointers (as
c@102 14 // numbers) means we can manage the Emscripten heap memory however we
c@102 15 // want in our request wrapper function below.
c@102 16
c@102 17 var vampipeRequestJson = exampleModule.cwrap(
c@102 18 'vampipeRequestJson', 'number', ['number']
c@102 19 );
c@102 20
c@102 21 var vampipeProcessRaw = exampleModule.cwrap(
c@102 22 "vampipeProcessRaw", "number", ["number", "number", "number", "number"]
c@102 23 );
c@102 24
c@102 25 var vampipeFreeJson = exampleModule.cwrap(
c@102 26 'vampipeFreeJson', 'void', ['number']
c@102 27 );
c@102 28
c@102 29 function note(blah) {
c@102 30 document.getElementById("test-result").innerHTML += blah + "<br>";
c@102 31 }
c@102 32
c@102 33 function comment(blah) {
c@102 34 note("<br><i>" + blah + "</i>");
c@102 35 }
c@102 36
c@102 37 function processRaw(request) {
c@102 38
c@102 39 const nChannels = request.processInput.inputBuffers.length;
c@102 40 const nFrames = request.processInput.inputBuffers[0].values.length;
c@102 41
c@102 42 const buffersPtr = exampleModule._malloc(nChannels * 4);
c@102 43 const buffers = new Uint32Array(
c@102 44 exampleModule.HEAPU8.buffer, buffersPtr, nChannels);
c@102 45
c@102 46 for (let i = 0; i < nChannels; ++i) {
c@102 47 const framesPtr = exampleModule._malloc(nFrames * 4);
c@102 48 const frames = new Float32Array(
c@102 49 exampleModule.HEAPU8.buffer, framesPtr, nFrames);
c@102 50 frames.set(request.processInput.inputBuffers[i].values);
c@102 51 buffers[i] = framesPtr;
c@102 52 }
c@102 53
c@102 54 const responseJson = vampipeProcessRaw(
c@102 55 request.pluginHandle,
c@102 56 buffersPtr,
c@102 57 request.processInput.timestamp.s,
c@102 58 request.processInput.timestamp.n);
c@102 59
c@102 60 for (let i = 0; i < nChannels; ++i) {
c@102 61 exampleModule._free(buffers[i]);
c@102 62 }
c@102 63 exampleModule._free(buffersPtr);
c@102 64
c@102 65 const response = JSON.parse(
c@102 66 exampleModule.Pointer_stringify(responseJson));
c@102 67
c@102 68 vampipeFreeJson(responseJson);
c@102 69
c@102 70 return response;
c@102 71 }
c@102 72
c@102 73 function request(jsonStr) {
c@102 74 note("Request JSON = " + jsonStr);
c@102 75 var m = exampleModule;
c@102 76 // Inspection reveals that intArrayFromString converts the string
c@102 77 // from utf16 to utf8, which is what we want (though the docs
c@102 78 // don't mention this). Note the *Cstr values are Emscripten heap
c@102 79 // pointers
c@102 80 var inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL);
c@102 81 var outCstr = vampipeRequestJson(inCstr);
c@102 82 m._free(inCstr);
c@102 83 var result = m.Pointer_stringify(outCstr);
c@102 84 vampipeFreeJson(outCstr);
c@102 85 note("Returned JSON = " + result);
c@102 86 return result;
c@102 87 }
c@102 88
c@102 89 function test() {
c@102 90
c@102 91 comment("Loading zero crossings plugin...");
c@102 92 let result = request('{"type":"load","content": {"pluginKey":"vamp-example-plugins:zerocrossing","inputSampleRate":44100,"adapterFlags":["AdaptAllSafe"]}}');
c@102 93
c@102 94 const blockSize = 1024;
c@102 95
c@102 96 result = request('{"type":"configure","content":{"pluginHandle":1,"configuration":{"blockSize": ' + blockSize + ', "channelCount": 1, "stepSize": ' + blockSize + '}}}');
c@102 97
c@102 98 const nblocks = 1000;
c@102 99
c@102 100 let processInputBuffers = [new Float32Array(
c@102 101 Array.from(Array(blockSize).keys(), n => n / blockSize))
c@102 102 ];
c@102 103
c@102 104 comment("Now processing " + nblocks + " blocks of 1024 samples each...");
c@102 105
c@102 106 let start = (new Date()).getTime();
c@102 107 comment("Start at " + start);
c@102 108
c@102 109 for (let i = 0; i < nblocks; ++i) {
c@102 110 let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it
c@102 111 result = processRaw({
c@102 112 "pluginHandle": 1,
c@102 113 "processInput": {
c@102 114 "timestamp": ts,
c@102 115 "inputBuffers": processInputBuffers
c@102 116 }
c@102 117 });
c@102 118 }
c@102 119
c@102 120 let finish = (new Date()).getTime();
c@102 121 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms");
c@102 122
c@102 123 comment("Again...");
c@102 124
c@102 125 start = (new Date()).getTime();
c@102 126 comment("Start at " + start);
c@102 127
c@102 128 for (let i = 0; i < nblocks; ++i) {
c@102 129 let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it
c@102 130 result = processRaw({
c@102 131 "pluginHandle": 1,
c@102 132 "processInput": {
c@102 133 "timestamp": ts,
c@102 134 "inputBuffers": processInputBuffers
c@102 135 }
c@102 136 });
c@102 137 }
c@102 138
c@102 139 finish = (new Date()).getTime();
c@102 140 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms");
c@102 141
c@102 142 comment("Cleaning up the plugin and getting any remaining features...");
c@102 143 result = request('{"type":"finish","content":{"pluginHandle":1}}');
c@102 144 }
c@102 145
c@102 146 window.onload = function() {
c@102 147 test();
c@102 148 }