[Perl] XS利用でPerl高速化

(追記:2009/03/25)
id:tokuhirom さんからコメントを頂きました。このベンチマークは問題があるそうです。
http://d.hatena.ne.jp/higepon/20050615/1118829090#c

(追記:終わり)
PerlにはC言語で書かれた関数を呼び出すためにXSという仕組みが存在します。
一部CPANモジュールでも使われているためご存知の方も多いと思いますが、今回はこのXSの簡単な利用方法を紹介したいと思います。
なおXSは、はてなでも使用しています。


さてXSモジュールを使うとうれしい事は

  • C言語で書くことにより、処理が高速になる可能性がある
  • 既存のC言語ライブラリ資産をPerlから利用することができる
  • Perlがあまり得意でない、メモリ内などに存在するビット単位での細かなデータ構造を、あれこれできる


などが挙げられると思います。
今回は、高速化について簡単に検証してみます。


早速 XS でモジュールを書いていきます。
作成するモジュールには以下のPerlサブルーチンと同じ機能を持ったものをXSで作成します。

sub increment2 {
    my $value = shift;
    $value += 2; # 2を足した値を返す
}


1. h2xsコマンド

mkdir xs
cd xs
h2xs -A -n MyTestXS

MyTestXSというディレクトリが作成され雛形のファイルたちが生成されます。

2. Makefileの生成

cd MyTestXS
perl Makefile.PL

3. xsファイルの編集
MyTestXS/MyTestXS.xsというファイルを編集します。

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"


MODULE = MyTestXS		PACKAGE = MyTestXS		

# ここから下に追記する

# 引数valueに 2 を足して返す関数
int 
increment2(value)
int value
CODE:
    RETVAL = value + 2;
OUTPUT:
    RETVAL


「ここから下に追記する」よりも上は、自動生成されたコードです。
C言語の関数宣言に似た形で、戻り値、関数名、引数の名前と型を指定します。
その後、CODE:部分に実際のCのコードを書いていきます。


戻り値は RETVAL = という形でセットしなければいけないので注意が必要です。
Cのコード部分が非常に短いので、とてもC言語に見えませんがこのコードが
実際にコンパイルされてPerl殻利用可能になります。


3. make
MyTestXS.xsの編集が終わったら、ビルドを行います。
make が正常終了すれば、ビルドは成功です。
エラーが出た場合は、メッセージを手がかりに修正後、再度makeしてみてください。


4. テストスクリプトの作成
test.plを作成します。

#!/usr/local/bin/perl -w
use strict;

use ExtUtils::testlib;
use MyTestXS;

print "100 + 2 = " . MyTestXS::increment2(100) . "\n";


実行してみます

./test.pl 
100 + 2 = 102


と表示されるはずです。


5. ベンチマーク
Benchmarkモジュールを利用して、Perl、XSそれぞれの increment モジュールを 500万回呼び出して比較してみました。

Benchmark: timing 5000000 iterations of XS, perl...
        XS:  2 wallclock secs ( 1.31 usr + -0.01 sys =  1.30 CPU) @ 3846153.85/s (n=5000000)
      perl:  3 wallclock secs ( 4.43 usr +  0.00 sys =  4.43 CPU) @ 1128668.17/s (n=5000000)


実用的でもなくあまり例が良くないのですが、3倍以上XSの方が速いことが分かります。
長くなったので今回はここまでということで。
次回?は更にXSの使いどころや、詳細に触れていきたいと思います。