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