XSを書く難しさ

最近思うが,つくづくXSは難しい。いとも簡単にSEGVを起こし,デバッグが難しく,それゆえモジュール作者のやる気が失われたときのリスクが非常に大きい。そうやって多大なリスクを犯してXSを書いても,肝心の速度がPurePerl以上に遅いことも少なくない。

最近だとClass::MOPにパッチを送ったのだけど,その後幾度かのバグフィクスや修正を経た0.72現在,パフォーマンスがかなり落ちている。

最初のパッチでのパフォーマンス(いずれもPerl 5.8.9 linux multi-thread with -DDEBUGGING):

Initialization:
     Rate   pp   xs
pp 2327/s   -- -18%
xs 2844/s  22%   --

Looking into the stash:
      Rate   pp   xs
pp 20958/s   -- -72%
xs 73770/s 252%   --

Getting the cache:
       Rate   pp   xs
pp 185579/s   -- -80%
xs 918728/s 395%   --

Class::MOP バージョン0.72:

Initialization:
     Rate  pp  xs
pp 2349/s  -- -1%
xs 2378/s  1%  --

Looking into the stash:
      Rate   pp   xs
pp 20479/s   -- -50%
xs 40959/s 100%   --

Getting the cache:
       Rate   pp   xs
pp 172463/s   -- -76%
xs 714566/s 314%   --

理由としては,現在のバージョンではPERL_NO_GET_CONTEXTを定義していないこと*1,シンボルテーブル(スタッシュ)を直接操作する代わりに内部でget_all_package_symbols()を呼んでいること*2などがあげられる。
彼らのようなエキスパートでさえ,このように「リファクタリング」によってパフォーマンスを落としてしまうほど,XSを書くのは難しい。

たまたま自分が関わったことなのでClass::MOPを扱ったが,別にClass::MOPの開発陣を批判したいのではない。たとえば,最初にClass::MOPへ送ったパッチにもバグが一つあったし*3,それ以外の自分が書いたXSにもまだバグはあるだろう。BやPadWalkerのバグのせいでData::Dump::Streamerが落ちるのは日常茶飯事である。XSを書くのは本当に難しい。
とはいえ,その苦労に値する効果があるからXSはやめられない!

*1:これはコードの本質とは関係ないが,Initializationの+20%はこのためだと思われる。

*2:これは「リファクタリング」の結果だが,その結果スタッシュの操作(Looking into the stash)の速度がほぼ半減した。

*3:紆余曲折した結果,まだそのバグは残っているようだ。あとで報告しなければ…。