annotate perf-test-node.js @ 34:0eafc96a039c

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