Mercurial > hg > piper-vamp-js
comparison perf-test.js @ 33:e9a0f66ee81c
Quick in-browser performance test
author | Chris Cannam |
---|---|
date | Sat, 24 Sep 2016 16:26:04 +0100 |
parents | |
children | 3faa4e3eedac |
comparison
equal
deleted
inserted
replaced
32:30028b3c95e4 | 33:e9a0f66ee81c |
---|---|
1 "use strict"; | |
2 | |
3 var exampleModule = VampExamplePluginsModule(); | |
4 | |
5 // It is possible to declare both parameters and return values as | |
6 // "string", in which case Emscripten will take care of | |
7 // conversions. But it's not clear how one would manage memory for | |
8 // newly-constructed returned C strings -- the returned pointer from | |
9 // vampipeRequestJson would appear (?) to be thrown away by the | |
10 // Emscripten string converter if we declare it as returning a string, | |
11 // so we have no opportunity to pass it to vampipeFreeJson, which | |
12 // suggests this would leak memory if the string isn't static. Not | |
13 // wholly sure though. Anyway, passing and returning pointers (as | |
14 // numbers) means we can manage the Emscripten heap memory however we | |
15 // want in our request wrapper function below. | |
16 | |
17 var vampipeRequestJson = exampleModule.cwrap( | |
18 'vampipeRequestJson', 'number', ['number'] | |
19 ); | |
20 | |
21 var vampipeProcessRaw = exampleModule.cwrap( | |
22 "vampipeProcessRaw", "number", ["number", "number", "number", "number"] | |
23 ); | |
24 | |
25 var vampipeFreeJson = exampleModule.cwrap( | |
26 'vampipeFreeJson', 'void', ['number'] | |
27 ); | |
28 | |
29 function note(blah) { | |
30 document.getElementById("test-result").innerHTML += blah + "<br>"; | |
31 } | |
32 | |
33 function comment(blah) { | |
34 note("<br><i>" + blah + "</i>"); | |
35 } | |
36 | |
37 function processRaw(request) { | |
38 | |
39 const nChannels = request.processInput.inputBuffers.length; | |
40 const nFrames = request.processInput.inputBuffers[0].values.length; | |
41 | |
42 const buffersPtr = exampleModule._malloc(nChannels * 4); | |
43 const buffers = new Uint32Array( | |
44 exampleModule.HEAPU8.buffer, buffersPtr, nChannels); | |
45 | |
46 for (let i = 0; i < nChannels; ++i) { | |
47 const framesPtr = exampleModule._malloc(nFrames * 4); | |
48 const frames = new Float32Array( | |
49 exampleModule.HEAPU8.buffer, framesPtr, nFrames); | |
50 frames.set(request.processInput.inputBuffers[i].values); | |
51 buffers[i] = framesPtr; | |
52 } | |
53 | |
54 const responseJson = vampipeProcessRaw( | |
55 request.pluginHandle, | |
56 buffersPtr, | |
57 request.processInput.timestamp.s, | |
58 request.processInput.timestamp.n); | |
59 | |
60 for (let i = 0; i < nChannels; ++i) { | |
61 exampleModule._free(buffers[i]); | |
62 } | |
63 exampleModule._free(buffersPtr); | |
64 | |
65 const response = JSON.parse( | |
66 exampleModule.Pointer_stringify(responseJson)); | |
67 | |
68 vampipeFreeJson(responseJson); | |
69 | |
70 return response; | |
71 } | |
72 | |
73 function request(jsonStr) { | |
74 note("Request JSON = " + jsonStr); | |
75 var m = exampleModule; | |
76 // Inspection reveals that intArrayFromString converts the string | |
77 // from utf16 to utf8, which is what we want (though the docs | |
78 // don't mention this). Note the *Cstr values are Emscripten heap | |
79 // pointers | |
80 var inCstr = m.allocate(m.intArrayFromString(jsonStr), 'i8', m.ALLOC_NORMAL); | |
81 var outCstr = vampipeRequestJson(inCstr); | |
82 m._free(inCstr); | |
83 var result = m.Pointer_stringify(outCstr); | |
84 vampipeFreeJson(outCstr); | |
85 note("Returned JSON = " + result); | |
86 return result; | |
87 } | |
88 | |
89 function test() { | |
90 | |
91 comment("Loading zero crossings plugin..."); | |
92 let result = request('{"type":"load","content": {"pluginKey":"vamp-example-plugins:zerocrossing","inputSampleRate":44100,"adapterFlags":["AdaptAllSafe"]}}'); | |
93 | |
94 const blockSize = 1024; | |
95 | |
96 result = request('{"type":"configure","content":{"pluginHandle":1,"configuration":{"blockSize": ' + blockSize + ', "channelCount": 1, "stepSize": ' + blockSize + '}}}'); | |
97 | |
98 const nblocks = 1000; | |
99 | |
100 let processInputBuffers = [new Float32Array( | |
101 Array.from(Array(blockSize).keys(), n => n / blockSize)) | |
102 ]; | |
103 | |
104 comment("Now processing " + nblocks + " blocks of 1024 samples each..."); | |
105 | |
106 let start = (new Date()).getTime(); | |
107 comment("Start at " + start); | |
108 | |
109 for (let i = 0; i < nblocks; ++i) { | |
110 let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it | |
111 result = processRaw({ | |
112 "pluginHandle": 1, | |
113 "processInput": { | |
114 "timestamp": ts, | |
115 "inputBuffers": processInputBuffers | |
116 } | |
117 }); | |
118 } | |
119 | |
120 let finish = (new Date()).getTime(); | |
121 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); | |
122 | |
123 comment("Again..."); | |
124 | |
125 start = (new Date()).getTime(); | |
126 comment("Start at " + start); | |
127 | |
128 for (let i = 0; i < nblocks; ++i) { | |
129 let ts = { "s": i, "n": 0 }; // wholly bogus, but ZC plugin doesn't use it | |
130 result = processRaw({ | |
131 "pluginHandle": 1, | |
132 "processInput": { | |
133 "timestamp": ts, | |
134 "inputBuffers": processInputBuffers | |
135 } | |
136 }); | |
137 } | |
138 | |
139 finish = (new Date()).getTime(); | |
140 comment("Finish at " + finish + " for a time of " + (finish - start) + " ms"); | |
141 | |
142 comment("Cleaning up the plugin and getting any remaining features..."); | |
143 result = request('{"type":"finish","content":{"pluginHandle":1}}'); | |
144 } | |
145 | |
146 window.onload = function() { | |
147 test(); | |
148 } |