annotate perf-test.js @ 38:946c965fd1eb

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