Emacs
EmacsDay 25

Emacsから Cの関数をつかう -> はやい

More than 3 years have passed since last update.

C言語で書いた関数を Emacsから呼び出したら速いかどうか検証してみた.

この機能は Emacs 25で搭載される予定の Dynamic module機能を使って実現しています. Dynamic module機能については以下の記事を参考にしてみてください


リポジトリ

https://github.com/syohex/emacs-fib


比較対象

フィボナッチ数の計算を以下のそれぞれで実装しました. C言語版 GCC 5.2.1でコンパイルし, 最適化オプションは -O2です. Emacs Lisp版は Emacs 25.0.50.1でバイトコンパイルしたものを利用しました.


  • Emacs Lisp再帰版

  • Emacs Lispループ版

  • C再帰版

  • Cループ版

(defun fib-elisp (n)

(if (<= n 1)
n
(+ (fib-elisp (1- n)) (fib-elisp (- n 2)))))

(defun fib-elisp-loop (n)

(cl-loop for a = 0 then b
and b = 1 then (+ a b)
repeat n
finally return a))

static intmax_t

fib(intmax_t n)
{
if (n <= 1)
return n;

return fib(n - 1) + fib(n - 2);
}

static intmax_t

fib_loop(intmax_t n)
{
int a = 0, b = 1;
for (int i = 0; i < n; ++i) {
int tmp = a;
a = b;
b = tmp + b;
}

return a;
}


ベンチマーク


環境


  • Ubuntu 15.10 x86_64 64bit

  • CPU: Intel(R) Core(TM) i7-2620M CPU @ 2.70GHz

  • Memory: 8GB

  • Emacs: 25.0.50.1(2015年 12月 25日ビルド)

  • GCC version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2) 最適化オプション -O2のみ


ベンチマークコード

以下のベンチマーク関数を n = 30, count=100で実行しました. 表示されるものは 100回実行したときの実行時間になります.

(defun fib-bench (n count)

(interactive
(list (read-number "Fibonacci number: ")
(read-number "Benchmark count: ")))
(benchmark count `(fib-elisp ,n))
(benchmark count `(fib-elisp-loop ,n))
(benchmark count `(fib-c ,n))
(benchmark count `(fib-c-loop ,n)))

(fib-bench 30 100)


結果

実行時間(秒)
比率(EmacsLisp再帰版との)

Emacs Lisp再帰
58.033767
1

Emacs Lispループ
0.001959
29624

C再帰
0.338148
172

Cループ
0.000044
1318949

題材が悪いというのもあるけど, Emacs Lispもアルゴリズムを適切に選べばそこまで遅くないという印象. 再帰版は論外レベルで遅いが.... Cでちゃんと書けば最も速そうだが, そこまで Cで書くのにこだわる必要もないように思えます. まだいろいろ試せてなさすぎなので, もっといろいろ見ていく必要はありますが...


その他

https://github.com/syohex/emacs-parson

parsonという JSONパーサのバインディングを書いて見ました. これと標準パッケージの json.elとベンチマークを行ってみたのですが, 短い入力だと decodeはともかく encodeは遅いという結果が得られました. 大きめの入力だと両方とも Cが速いという結果が得られたのですが, 見極めにはもう少し時間がかかりそうです.


おわりに

本当は golangで使った shared libraryでいろいろ試すということを検討していたのですが, golangのランタイムで Segmentation faultが出る問題が解決できなかったのでこのような簡易な内容になってしまったことをお詫び申し上げます.

また mrubyネタの拡張を行おうかとも思っていたのですが, 現状の私の mrubyの知識が乏しすぎて実現することができませんでした. これはお正月に勉強してなんとかしようと思いますが, こちらについても合わせてお詫び申し上げます.