JavaScript
WASM
残念ながら、Edgeはまだ対応してないです。
WASMを使うなら、JSのバージョンも提供しないといけません。
EmscriptenのCコンパイラー、emccを使用します。
Emscriptenのビルドは数時間かかります。
emcc -o hello.js hello.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_hello']"
#include <stdio.h>
void hello() {
printf("Hello, world!\n");
}
-s WASMをつけないとasm.jsを出します
Module.ccall(
'hello', // 関数名
null, // 返却値の型
[], // 引数の型
[], // 引数の値
);
cwrapで同じように関数のラッパーを作成できます。
<html>
<head>
<title>Hello, world!</title>
</head>
<body>
<p>Check the log</p>
<script>
var Module = {
onRuntimeInitialized: function() {
Module.ccall('hello', null, [], []);
},
};
</script>
<script src="hello.js"></script>
</body>
</html>
Emscriptenのランタイムは便利関数をたくさん定義してくれています。
#include <string.h>
void upper(char *dst, char *src) {
int i;
int l = strlen(src);
for (i = 0; i < l; i++) {
char c = src[i];
if (c >= 'a' && c <= 'z') {
dst[i] = c - ('a' - 'A');
} else {
dst[i] = c;
}
}
dst[l] = '\0';
}
function handleInput(event) {
const value = event.target.value;
// メモリを割り当てる
const src = allocate(intArrayFromString(value), 'i8', ALLOC_NORMAL);
const dst = _malloc(value.length + 1);
Module.ccall(
'upper',
null,
['number', 'number'],
[dst, src],
);
const result = Pointer_stringify(dst);
_free(src); // メモリリークを起こさないようにメモリ解放
_free(dst);
output.innerHTML = result;
}
画像の勾配のマグニチュードを計算します。畳み込みなので結構重い処理です!
void sobel(unsigned char *dst, unsigned char *src, int width, int height) {
int pixelX, pixelY, mag;
for (int i = 1; i < height - 1; i = i + 1) {
for (int j = 1; j < width - 1; j = j + 1) {
pixelX = (-1 * getPixel(src, i - 1, j - 1, width)) +
(1 * getPixel(src, i - 1, j + 1, width)) +
(-2 * getPixel(src, i, j - 1, width)) +
(2 * getPixel(src, i, j + 1, width)) +
(-1 * getPixel(src, i + 1, j - 1, width)) +
(1 * getPixel(src, i + 1, j + 1, width));
pixelY = (-1 * getPixel(src, i - 1, j - 1, width)) +
(-2 * getPixel(src, i - 1, j, width)) +
(-1 * getPixel(src, i - 1, j + 1, width)) +
(1 * getPixel(src, i + 1, j - 1, width)) +
(2 * getPixel(src, i + 1, j, width)) +
(1 * getPixel(src, i + 1, j + 1, width));
mag = ceil(sqrt(pixelX * pixelX + pixelY * pixelY));
if (mag > 255) {
mag = 255;
}
dst[i * 4 * width + 4 * j] = mag;
dst[i * 4 * width + 4 * j + 1] = mag;
dst[i * 4 * width + 4 * j + 2] = mag;
dst[i * 4 * width + 4 * j + 3] = 255;
}
}
}
最適化のオプションを指定できます。
emcc -o sobel.js sobel.c -lm -O3 -s WASM=1 -s EXPORTED_FUNCTIONS="['_sobel']"
Emscriptenが出しているasm.jsのパフォーマンスはWASMとあまり変わらないです。
wasmのパフォーマンスは自分で書いたJSより2倍以上速いです。
初期ロードはasm.jsとwasmはあまり変わらないですが、もっと大きいプロジェクトだと違いが出ると思います。