asm.jsの雛型
今すぐにコピーして使えるHTML5 の雛形を紹介します。
必要最低限+使いやすさを加味したコードにしています。
<!DOCTYPE html>
<html lang=”ja”>
<head>
<meta charset=”utf-8″/>
<script>
//(1) asm.js関数宣言
function asm(stdin, foreign, heap){
//(2) use asm宣言
”use asm”;
//(3) インポート宣言
//functions
var acos = stdin.Math.acos;
var asin = stdin.Math.asin;
var atan = stdin.Math.atan;
var cos = stdin.Math.cos;
var sin = stdin.Math.sin;
var tan = stdin.Math.tan;
var exp = stdin.Math.exp;
var log = stdin.Math.log;
var ceil = stdin.Math.ceil;
var floor = stdin.Math.floor;
var sqrt = stdin.Math.sqrt;
var abs = stdin.Math.abs;
var min = stdin.Math.min;
var max = stdin.Math.max;
var atan2 = stdin.Math.atan2;
var pow = stdin.Math.pow;
var imul = stdin.Math.imul; //int型の掛け算に用いる
var fround = stdin.Math.fround; //float型への変換に用いる
//constants
var E = stdin.Math.E;
var LN10 = stdin.Math.LN10;
var LN2 = stdin.Math.LN2;
var LOG2E = stdin.Math.LOG2E;
var LOG10E = stdin.Math.LOG10E;
var PI = stdin.Math.PI;
var SQRT1_2 = stdin.Math.SQRT1_2;
var SQRT2 = stdin.Math.SQRT2;
//
var callOuter = foreign.callOuter;
//(4) 共有変数宣言
var pI = 0; //int
var pF = fround(0); //float
var pD = 0.0; //double
var pArray = new stdin.Float32Array(heap);
//(5) 関数定義
function fCalculation_Asm(G0,vi0,G1,vi1){
// 引数
G0 = fround(G0);
vi0 = fround(vi0);
G1 = fround(G1);
vi1 = fround(vi1);
// ローカル変数の定義
var vI = 0; //int
var vF = fround(0); //float
for(vI=1; (vI|0)<100000; vI=(vI+1)|0){
vF = fround(vF + fround(fround(G0 * vi0) + fround(G1 * vi1)));
}
// 戻り値
return fround(vF);
}
//(6) 外部への公開
return {
fCalculation_Asm: fCalculation_Asm,
};
}
//(7) asm.jsモジュールの呼び出し
let asmmod = asm(self, {callOuter: function(){}}, new ArrayBuffer(0x10000));
//
function fCalculation_Normal(G0,vi0,G1,vi1){
var vF = 0;
for(var i=1; i<100000; i++){
vF += (G0 * vi0 + G1 * vi1);
}
return vF;
}
window.onload = function() {
oLog = document.getElementById(‘dLog’);
//★通常のjavascriptタイマーテスト
// 開始時間を計測
pCnt = 0;
pS_1 = performance.now();
var id1 = setInterval(function(){
pCnt++;
// 計測する関数
var v1 = fCalculation_Normal(1,2,3,4);
// 現在時間を計測
pE_1 = performance.now(); // 現在時間
pT_1 = Math.floor(pE_1 pS_1);
// 終了処理 (60fpsの処理で1秒経過したら終了)
if(pT_1 >= 1000){
clearInterval(id1);
oLog.innerHTML += “<br>”+ pT_1 +”ms秒間の処理” + pCnt + “回 (normal)” + v1;
}}, 1000 / 60);
//★asm.jsのjavascriptタイマーテスト
// 開始時間を計測
pCnt = 0;
pS_2 = performance.now();
var id2 = setInterval(function(){
pCnt++;
// 計測する関数
var v2 = asmmod.fCalculation_Asm(1,2,3,4);
// 現在時間を計測
pE_2 = performance.now(); // 現在時間
pT_2 = Math.floor(pE_2 pS_2);
//終了処理 (60fpsの処理で1秒経過したら終了)
if(pT_2 >= 1000){
clearInterval(id2);
oLog.innerHTML += “<br>”+ pT_2 +”ms秒間の処理” + pCnt + “回 (asm.js)” + v2;
}}, 1000 / 60);
}
</script>
</head>
<body>
<div id=’dLog’></div>
</body>
</html>
(4) 共有変数宣言
・共通変数を使うと処理が遅くなるのでローカル変数を使う方が良いです。
・変数の初期値には、複雑な値の指定はできないので「0」を代入します。
var pI = 0; : int型の変数の宣言
var pF = fround(0); : float型
var pD = 0.0; : double型
・heapに対する型付き配列(ArrayBufferView)の生成は共有変数宣言部でのみ可能です。
var pArray = new stdin.Float32Array(heap);
(5) 関数定義
・引数の型を設定します。
i = i|0; : int型の引数
f = fround(f); : float型の引数
d = +d; : double型の引数
・ローカル変数を定義します。初期値には「0」を代入します。
var vI = 0; : int型の変数の宣言
var vF = fround(0); : float型
var vD = 0.0; : double型
・計算を行います。2つの値の四則演算を行うたびに、型の指定が必要になります。
※asm.js を使う場合
for(vI=1; (vI|0)<100000; vI=(vI+1)|0){
vF = fround(vF + fround(fround(G0 * vi0) + fround(G1 * vi1)));
}
※asm.js を使わない場合 (普通のJavaScript)
for(var i=1; i<100000; i++){
vF += (G0 * vi0 + G1 * vi1);
}
・戻り値の型の指定を行います。既に指定が行われている場合は不要です。
return i|0; : int型の変数の宣言
return fround(f); : float型
return +d; : double型
速度検証における注意事項
・雛形コードでは、「fCalculation_Asm」と「fCalculation_Normal」の速度の比較を行っています。
・正しい結果を得るためには2つの関数共に、同様の計算過程を行う必要があります。
・「int型」>「float型」>「double型」の順で計算速度が遅くなります。
・asm.jsは関数callに非常に時間が掛かる為、関数を何度も呼び出すと普通のJavaScriptよりも遅くなります。
・DOM等による描画処理を行う場合は、「fps60」より早い計算は不要となります。
fps60 の処理に間に合わないJavaScriptの場合のみasm.jsが有効になります。