WebAssembly LERP C++
The following example demonstrates how to use a WebAssembly binary in a PeerMR job. It is based off of the Emscripten LERP C++ example. The binary is a simple linear interpolation function written in C++ and compiled to WebAssembly using Emscripten. PeerMR can be used to run this in a distributed manner across multiple browsers.
First, create the C++ source lerp.cpp
:
#include <emscripten/bind.h>
using namespace emscripten;
float lerp(float a, float b, float t) {
return (1 - t) * a + t * b;
}
EMSCRIPTEN_BINDINGS(my_module) {
function("lerp", &lerp);
}
Next, compile it to WebAssembly using Emscripten:
emcc -lembind -O0 -s ENVIRONMENT=worker -s EXPORT_NAME="LerpModule" -s MODULARIZE=1 -o lerp.js lerp.cpp
-O0
optimizes the binary for size.
-s ENVIRONMENT=worker
sets the environment to a web worker which is the execution environment for PeerMR jobs.
-s EXPORT_NAME="LerpModule"
sets the name of the exported module.
-s MODULARIZE=1
wraps the output in a module to not pollute the global namespace.
-o lerp.js
specifies the output file.
This will generate two files: lerp.js
and lerp.wasm
. The lerp.js
file is a JavaScript wrapper around the WebAssembly binary.
Both files are needed to run the WebAssembly binary in a browser.
Make these files available as public URLs, for example by uploading them to a cloud storage service.
In this example, we will use GCS and assume the bucket name is lerpbucket
.
Next, create a PeerMR job that uses the WebAssembly binary:
const execution = new JobExecution(storageType = 'pmrfs');
execution.workerCount = 2;
// lerp.js will fetch the WASM binary
execution.scripts = ['https://storage.googleapis.com/lerpbucket/lerp.js'];
// register the URL of each WASM binary that the job needs
execution.wasmBinaries = ['https://storage.googleapis.com/lerpbucket/lerp.wasm'];
execution.setInputFn(async function input() {
return [
[0.0, 1.0, 0.5],
[0.0, 1.0, 0.25],
[0.0, 1.0, 0.75],
[0.0, 1.0, 0.1],
[0.0, 1.0, 0.9],
[0.0, 1.0, 0.0],
[0.0, 1.0, 1.0]
];
});
execution.addStage(new MapStage(async function map(x) {
// import the LerpModule
// use `context.getWebAssemblyURL` to specify the URL of the WASM binary
const lerpModule = await LerpModule({
locateFile: function (path) {
if (path.endsWith('.wasm')) {
return context.getWebAssemblyURL('lerp.wasm');
}
return path;
}
});
// lerp each value
for await (const kv of x) {
let [k, v] = kv;
context.emit(k, lerpModule.lerp(v[0], v[1], v[2]));
}
await context.onComplete();
}));
execution.start(jobRunner);