でーたさいえんすって何それ食えるの?

JuliaとかRとかPythonとかと戯れていたい

R 3.4.0 のJITバイトコンパイラってどんくらい早くなるの?

R3.4.0がリリースされましたね。

で、大きな変更点のひとつにJITバイトコンパイラがデフォルトでONになってるとのことです。
これによって、forループやfunctionは特に何もせずともバイトコンパイルが行われて高速化が行われることになります。
※ただしbrowser()が入れられた関数はバイトコンパイル対象外になります。
コンパイルが不要なときは、compiler::enableJIT(0)または環境変数のR_ENABLE_JITを0にすればOKです

他にも色々アップデート情報の詳細はこちら
R: R News

で、RStudioもこのバイトコンパイル機能に対応したアップデートが行われたそうです。

cmpfun()使うとけっこう早くなるんだよなー。。。程度には覚えていたものの 具体的にどんだけ早いの?に対してはよく覚えてないので
このバイトコンパイラでどんだけ早くなったのか? を実際にやって記録を残しておきたいと思います。。

実行環境

MacbookAir macOS Sierra/2GHz Intel Core i7(2core 4thread)/8GB DDR3 Memory

チェック方法

forループを長めに回して、中で変数をインクリメントするだけの処理を走らせます。 この処理を100回走らせ平均を出してみました。 実際のスクリプトは次の通りです。

n_test <- 100
time_diff <- array(n_test)

loop_end <- 10^7
buf_in_loop <- 1

for(j in 1:n_test){
 time_start <- Sys.time()
 for(i in 1:loop_end){
  buf_in_loop <- buf_in_loop + 1
 }
 time_end <- Sys.time()
 time_diff[j] <- time_end - time_start
}

print(mean(time_diff))
hist(time_diff, breaks = seq(0,5,length.out = 30))

結果

R3.3.3 : 3.500181 sec on average
R3.4.0 : 0.366924 sec on average ※R3.4.0でcompiler::enableJIT(0)にして実行するとR3.3.3と同様でした

約10倍早い!

諸条件でここまでパフォーマンスが出ないケース(*1)もありそうですが
デフォでこんだけ高速化されるなら、Rでも躊躇わずループ書いても良さそうですね。

f:id:masato_613:20170425063949p:plain f:id:masato_613:20170425063943p:plain

ついでなのでfor()で1:loop_endとしている所で、 配列を生成してメモリ食っちゃうハズだけど、コンパイラーが有効だとどうなるか?もチェック
これは、profiler()でメモリの最も消費の多かった所を平均しました。

R3.3.3 : 34.27 MB on average
R3.4.0 : 0.058 MB on average
メモリ消費もだいぶ抑えられてて良い感じですね!!
一番メモリを消費してたのは、どちらもfor()の部分でした。

*1 例えば、forの中で走査してくベクトルを生成しないようにwhile()にするなんてハックだと 同じコードで平均 0.88秒くらいになり、倍以上の処理時間がかかってしまいます。 多分、値の代入がインクリメントする変数の分増えるので、そこが原因かな?と想像できます。