asm.jsを触ってみたので所感など。
asm.jsはJavaScriptのサブセットで、限られた型しか使えないが高速に動作する言語との事。とりあえずどの程度速くなるのか、計算量が多くなるfibonacciの実装で試してみた。参考資料はasm.jsの仕様ぐらいしか無かったのでこれを見ながら。
で、実際に書いてみると型がゆるゆるなJavaScriptのイメージは脆くも崩れ去り、厳格な型チェックの世界である事がわかった。コンパイル言語を書いている時の頭に切り換えないと、コンパイルエラーと延々格闘する事になる。まずはasm.jsのコードは次の形式で、module exportする。
関数の書き型にも決まりがあり、次の順番で記述する必要がある。
次にasm.jsで書く関数の引数の型、戻り値の型を決める。引数の型はParameter Type Annotationsで記述する。
仕様にはintとdoubleしか無いのでどちらかとなる。
関数の戻り値はReturn Type Annotationsで記述する。関数内にreturnが複数個ある場合、それぞれの箇所でreturnの型が異なるとコンパイルできない。
で、実際にフィボナッチが動くコードと実行結果が以下。実行はAuroraバージョン22.0a2。
asm.jsの方が速いのがわかる。といってもこの程度ならまだしも、実際に高速化したい処理を手でasm.jsで書くのは正直厳しいという印象。githubで "use asm"しているコードを探したら行列演算ライブラリが出てきましたが、ヒープ操作している所が全く読めなくてやばい。asm.jsはJavaScriptのサブセットで、限られた型しか使えないが高速に動作する言語との事。とりあえずどの程度速くなるのか、計算量が多くなるfibonacciの実装で試してみた。参考資料はasm.jsの仕様ぐらいしか無かったのでこれを見ながら。
で、実際に書いてみると型がゆるゆるなJavaScriptのイメージは脆くも崩れ去り、厳格な型チェックの世界である事がわかった。コンパイル言語を書いている時の頭に切り換えないと、コンパイルエラーと延々格闘する事になる。まずはasm.jsのコードは次の形式で、module exportする。
1 2 3 4 5 6 7 8 9 10 11 12 | function create_my_asm_module(stdlib, foreign, heap) { "use asm" ; function hoge() {...} function fuga() {...} return { hoge: hoge, fuga: fuga } } asm_my_modules = create_my_asm_module(window); |
1 2 3 4 5 6 | function hoge(fuga) { // 1)パラメータの型指定 // 2)変数の初期化 // 3)処理 // 4)return句 } |
1 2 3 4 5 6 | function calc_tax_included_price(price, tax_rate) { price = price|0; // priceはint tax_rate = +tax_rate; // tax_rateはdouble //略 } |
関数の戻り値はReturn Type Annotationsで記述する。関数内にreturnが複数個ある場合、それぞれの箇所でreturnの型が異なるとコンパイルできない。
1 2 3 4 | return +d; // double return i|0; // signed int return 1; // double return ; // void |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function fast_fib_module(stdlib, foreign, heap) { | |
"use asm"; | |
function fib(n) { | |
n = n|0; | |
// nはint(符号の有無が不明の状態) | |
// 3はfixnum(0~2^31) | |
// 比較するためにnをシフト演算でunsignedに変換する | |
if (n >>> 0 < 3) { | |
return 1|0; | |
} | |
// fibの引数の型はintなのでintのサブセットであるsigned intで渡す | |
return (fib((n-1)|0) + fib((n-2)|0))|0; | |
} | |
return { | |
fib:fib | |
}; | |
} | |
fast_fib = fast_fib_module(window).fib; | |
function slow_fib(n) { | |
if (n < 3) { | |
return 1; | |
} | |
return slow_fib(n-1) + slow_fib(n-2); | |
} | |
function fast_check(n) { | |
console.time("ASM:fib(" + n + ")"); | |
console.log(fast_fib(n)); | |
console.timeEnd("ASM:fib(" + n + ")"); | |
} | |
function slow_check(n) { | |
console.time("NORMAL:fib(" + n + ")"); | |
console.log(slow_fib(n)); | |
console.timeEnd("NORMAL:fib(" + n + ")"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[01:40:15.035] fast_check(35) | |
[01:40:15.037] undefined | |
[01:40:15.037] ASM:fib(35): タイマー開始 | |
[01:40:15.076] 9227465 | |
[01:40:15.076] ASM:fib(35): 39ms | |
-- | |
[01:40:21.539] slow_check(35) | |
[01:40:21.541] undefined | |
[01:40:21.541] NORMAL:fib(35): タイマー開始 | |
[01:40:26.163] 9227465 | |
[01:40:26.163] NORMAL:fib(35): 4622ms |
mat-asm.js/mat.js at master · ruediger/mat-asm.js · GitHub
https://github.com/ruediger/mat-asm.js/blob/master/mat.js
https://github.com/ruediger/mat-asm.js/blob/master/mat.js