annotate test/perf-test-node.js @ 56:49a9c10bd980

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