annotate perf-test-node.js @ 104:2b20e610c4c2

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