LoginSignup
15
14

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-12-25

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

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

リポジトリ

比較対象

フィボナッチ数の計算を以下のそれぞれで実装しました. 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で書くのにこだわる必要もないように思えます. まだいろいろ試せてなさすぎなので, もっといろいろ見ていく必要はありますが...

その他

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

おわりに

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

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

15
14
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14