annotate perf-test-node.js @ 39:a9dbf9f45896 jsonrpc

Update adapter code
author Chris Cannam
date Wed, 05 Oct 2016 18:00:58 +0100
parents 34480328bf5c
children a734a7e976fa
rev   line source
Chris@34 1 "use strict";
Chris@34 2
Chris@34 3 var VampExamplePlugins = require("./VampExamplePlugins");
Chris@35 4 var base64 = require("./base64");
Chris@34 5 var exampleModule = VampExamplePlugins();
Chris@34 6
Chris@34 7 // It is possible to declare both parameters and return values as
Chris@34 8 // "string", in which case Emscripten will take care of
Chris@34 9 // conversions. But it's not clear how one would manage memory for
Chris@34 10 // newly-constructed returned C strings -- the returned pointer from
Chris@34 11 // vampipeRequestJson would appear (?) to be thrown away by the
Chris@34 12 // Emscripten string converter if we declare it as returning a string,
Chris@34 13 // so we have no opportunity to pass it to vampipeFreeJson, which
Chris@34 14 // suggests this would leak memory if the string isn't static. Not
Chris@34 15 // wholly sure though. Anyway, passing and returning pointers (as
Chris@34 16 // numbers) means we can manage the Emscripten heap memory however we
Chris@34 17 // want in our request wrapper function below.
Chris@34 18
Chris@34 19 var vampipeRequestJson = exampleModule.cwrap(
Chris@34 20 'vampipeRequestJson', 'number', ['number']
Chris@34 21 );
Chris@34 22
Chris@34 23 var vampipeProcessRaw = exampleModule.cwrap(
Chris@34 24 "vampipeProcessRaw", "number", ["number", "number", "number", "number"]
Chris@34 25 );
Chris@34 26
Chris@34 27 var vampipeFreeJson = exampleModule.cwrap(
Chris@34 28 'vampipeFreeJson', 'void', ['number']
Chris@34 29 );
Chris@34 30
Chris@34 31 function note(blah) {
Chris@34 32 console.log(blah);
Chris@34 33 }
Chris@34 34
Chris@34 35 function comment(blah) {
Chris@34 36 console.log(blah);
Chris@34 37 }
Chris@34 38
Chris@34 39 function processRaw(request) {
Chris@34 40
Chris@34 41 const nChannels = request.processInput.inputBuffers.length;
Chris@36 42 const nFrames = request.processInput.inputBuffers[0].length;
Chris@34 43
Chris@34 44 const buffersPtr = exampleModule._malloc(nChannels * 4);
Chris@34 45 const buffers = new Uint32Array(
Chris@34 46 exampleModule.HEAPU8.buffer, buffersPtr, nChannels);
Chris@34 47
Chris@34 48 for (let i = 0; i < nChannels; ++i) {
Chris@34 49 const framesPtr = exampleModule._malloc(nFrames * 4);
Chris@34 50 const frames = new Float32Array(
Chris@34 51 exampleModule.HEAPU8.buffer, framesPtr, nFrames);
Chris@36 52 frames.set(request.processInput.inputBuffers[i]);
Chris@34 53 buffers[i] = framesPtr;
Chris@34 54 }
Chris@34 55
Chris@34 56 const responseJson = vampipeProcessRaw(
Chris@34 57 request.pluginHandle,
Chris@34 58 buffersPtr,
Chris@34 59 request.processInput.timestamp.s,
Chris@34 60 request.processInput.timestamp.n);
Chris@34 61
Chris@34 62 for (let i = 0; i < nChannels; ++i) {
Chris@34 63 exampleModule._free(buffers[i]);
Chris@34 64 }
Chris@34 65 exampleModule._free(buffersPtr);
Chris@34 66
Chris@36 67 const responseJstr = exampleModule.Pointer_stringify(responseJson);
Chris@36 68 const response = JSON.parse(responseJstr);
Chris@34 69
Chris@34 70 vampipeFreeJson(responseJson);
Chris@34 71
Chris@34 72 return response;
Chris@34 73 }
Chris@34 74
Chris@35 75 function makeTimestamp(seconds) {
Chris@35 76 if (seconds >= 0.0) {
Chris@35 77 return {
Chris@35 78 s: Math.floor(seconds),
Chris@35 79 n: Math.floor((seconds - Math.floor(seconds)) * 1e9 + 0.5)
Chris@35 80 };
Chris@35 81 } else {
Chris@35 82 const { s, n } = makeTimestamp(-seconds);
Chris@35 83 return { s: -s, n: -n };
Chris@35 84 }
Chris@35 85 }
Chris@35 86
Chris@35 87 function frame2timestamp(frame, rate) {
Chris@35 88 return makeTimestamp(frame / rate);
Chris@35 89 }
Chris@35 90
Chris@34 91 function request(jsonStr) {
Chris@34 92 note("Request JSON = " + jsonStr);
Chris@34 93 var m = exampleModule;
Chris@34 94 // Inspection reveals that intArrayFromString converts the string
Chris@34 95 // from utf16 to utf8, which is what we want (though the docs
Chris@34 96 // don't mention this). Note the *Cstr values are Emscripten heap
Chris@34 97 // pointers
Chris@34 98 var inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL);
Chris@34 99 var outCstr = vampipeRequestJson(inCstr);
Chris@34 100 m._free(inCstr);
Chris@34 101 var result = m.Pointer_stringify(outCstr);
Chris@34 102 vampipeFreeJson(outCstr);
Chris@34 103 note("Returned JSON = " + result);
Chris@34 104 return result;
Chris@34 105 }
Chris@34 106
Chris@35 107 function myFromBase64(b64) {
Chris@35 108 while (b64.length % 4 > 0) { b64 += "="; }
Chris@35 109 let conv = new Float32Array(base64.toByteArray(b64).buffer);
Chris@35 110 return conv;
Chris@35 111 }
Chris@35 112
Chris@35 113 function convertWireFeature(wfeature) {
Chris@35 114 let out = {};
Chris@35 115 if (wfeature.timestamp != null) {
Chris@35 116 out.timestamp = wfeature.timestamp;
Chris@35 117 }
Chris@35 118 if (wfeature.duration != null) {
Chris@35 119 out.duration = wfeature.duration;
Chris@35 120 }
Chris@35 121 if (wfeature.label != null) {
Chris@35 122 out.label = wfeature.label;
Chris@35 123 }
Chris@36 124 const vv = wfeature.featureValues;
Chris@36 125 if (vv != null) {
Chris@36 126 if (typeof vv === "string") {
Chris@36 127 out.featureValues = myFromBase64(vv);
Chris@36 128 } else {
Chris@36 129 out.featureValues = new Float32Array(vv);
Chris@36 130 }
Chris@35 131 }
Chris@35 132 return out;
Chris@35 133 }
Chris@35 134
Chris@35 135 function convertWireFeatureList(wfeatures) {
Chris@35 136 return wfeatures.map(convertWireFeature);
Chris@35 137 }
Chris@35 138
Chris@35 139 function responseToFeatureSet(response) {
Chris@35 140 const features = new Map();
Chris@35 141 const processResponse = response.content;
Chris@35 142 const wireFeatures = processResponse.features;
Chris@35 143 Object.keys(wireFeatures).forEach(key => {
Chris@35 144 return features.set(key, convertWireFeatureList(wireFeatures[key]));
Chris@35 145 });
Chris@35 146 return features;
Chris@35 147 }
Chris@35 148
Chris@34 149 function test() {
Chris@34 150
Chris@35 151 const rate = 44100;
Chris@35 152
Chris@34 153 comment("Loading zero crossings plugin...");
Chris@35 154 let result = request('{"type":"load","content": {"pluginKey":"vamp-example-plugins:zerocrossing","inputSampleRate":' + rate + ',"adapterFlags":["AdaptAllSafe"]}}');
Chris@34 155
Chris@34 156 const blockSize = 1024;
Chris@34 157
Chris@34 158 result = request('{"type":"configure","content":{"pluginHandle":1,"configuration":{"blockSize": ' + blockSize + ', "channelCount": 1, "stepSize": ' + blockSize + '}}}');
Chris@34 159
Chris@34 160 const nblocks = 1000;
Chris@34 161
Chris@35 162 const makeBlock = (n => {
Chris@35 163 return {
Chris@35 164 timestamp : frame2timestamp(n * blockSize, rate),
Chris@35 165 inputBuffers : [
Chris@36 166 new Float32Array(Array.from(Array(blockSize).keys(),
Chris@36 167 n => n / blockSize))
Chris@35 168 ],
Chris@35 169 }
Chris@35 170 });
Chris@35 171
Chris@35 172 const blocks = Array.from(Array(nblocks).keys(), makeBlock);
Chris@34 173
Chris@34 174 comment("Now processing " + nblocks + " blocks of 1024 samples each...");
Chris@34 175
Chris@35 176 let total = 0;
Chris@35 177
Chris@34 178 let start = (new Date()).getTime();
Chris@34 179 comment("Start at " + start);
Chris@34 180
Chris@34 181 for (let i = 0; i < nblocks; ++i) {
Chris@34 182 result = processRaw({
Chris@34 183 "pluginHandle": 1,
Chris@35 184 "processInput": blocks[i]
Chris@34 185 });
Chris@35 186 let features = responseToFeatureSet(result);
Chris@36 187 let count = features.get("counts")[0].featureValues[0];
Chris@35 188 total += count;
Chris@34 189 }
Chris@34 190
Chris@34 191 let finish = (new Date()).getTime();
Chris@34 192 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms");
Chris@34 193
Chris@35 194 comment("Total = " + total);
Chris@35 195
Chris@34 196 comment("Again...");
Chris@35 197
Chris@35 198 total = 0;
Chris@34 199
Chris@34 200 start = (new Date()).getTime();
Chris@34 201 comment("Start at " + start);
Chris@34 202
Chris@34 203 for (let i = 0; i < nblocks; ++i) {
Chris@34 204 result = processRaw({
Chris@34 205 "pluginHandle": 1,
Chris@35 206 "processInput": blocks[i]
Chris@34 207 });
Chris@35 208 let features = responseToFeatureSet(result);
Chris@36 209 let count = features.get("counts")[0].featureValues[0];
Chris@35 210 total += count;
Chris@34 211 }
Chris@34 212
Chris@34 213 finish = (new Date()).getTime();
Chris@34 214 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms");
Chris@34 215
Chris@35 216 comment("Total = " + total);
Chris@35 217
Chris@34 218 comment("Cleaning up the plugin and getting any remaining features...");
Chris@34 219 result = request('{"type":"finish","content":{"pluginHandle":1}}');
Chris@34 220 }
Chris@34 221
Chris@34 222 test();
Chris@34 223