annotate perf-test-node.js @ 103:f7b53c0faa53

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