libc同梱のPOSIX regexpを使うmgemを公開した - ローファイ日記

ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

libc同梱のPOSIX regexpを使うmgemを公開した

こちらです。

github.com

とにかくカジュアルに、簡単でもいいので正規表現を使いたい場面にマッチすると思う。


簡単なベンチを取った。

他の主要な3つのmgem(mruby-onig-regexp/mruby-regexp-pre/mruby-pure-regexp)と比較して、結果的に mruby-posix-regexp が一番ビルド時間、バイナリサイズともに小さくなるという結果になった。

ベンチの内容

まず、 mruby 3.0.0 において、以下ような最小限の build_config.rb を用いた。

MRuby::Build.new do |conf|
  conf.toolchain

  conf.gem mgem: 'mruby-onig-regexp'
  #conf.gem mgem: 'mruby-regexp-pcre'
  #conf.gem mgem: 'mruby-pure-regexp'
  #conf.gem mgem: 'mruby-posix-regexp'
  conf.gem core: 'mruby-bin-mruby'
end

比較内容として、

  • rake deep_clean 後に一からビルドした際のビルド所要時間
  • 生成された mruby バイナリのサイズ

を比較した。コマンドの例:

$ rake deep_clean
$ time env MRUBY_CONFIG=onig_re rake
....
real    0m44.950s
user    0m38.223s
sys     0m2.880s

$ ls -l bin/mruby 
-rwxrwxr-x 1 vagrant vagrant 5532312 Sep 22 16:03 bin/mruby

またパフォーマンスのベンチとして、以下のスクリプトを走らせた。

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
text = ([text] * 100).join ' '

r = 0
100.times do
  r = text.scan(/\w+/).size
end
# mruby-io を含まないので例外で件数を出力している
raise "size of words: #{r}"

なお、正常に終了した場合 6900 を出力する。

$ time ./bin/mruby ../scan.rb
trace (most recent call last):
../scan.rb:8: size of words: 6900 (RuntimeError)

real    0m1.084s
user    0m1.071s
sys     0m0.013s

検証環境は 15 コア、8GBのメモリを割り当てたVirtualBox上のVM(母艦のMacIntel(R) Core(TM) i9-9980HK CPU @ 2.40GHz、16コア)とした。ただ、mrubyは並行ビルドや並行実行をしないのでコア数の影響は小さいのではないかと思う。

検証結果

- onig pcre pure posix
ビルド所要時間(s) 44.95 33.745 29.37 27.699
バイナリサイズ(bytes) 5532312 4477416 4137960 3956200
ベンチ時間(s) 1.084 5.395 -(*1) 4.307

(*1) 実行中にOOMによりKillされてしまったため計測できず。実行結果の出力を参考までに:

$ time ./bin/mruby ../scan.rb
Killed

real    0m5.271s
user    0m2.508s
sys     0m2.751s

グラフ

f:id:udzura:20210924164206p:plain

考察

  • 依存ライブラリを小さく(より正確には、C拡張として外部ライブラリをビルドしないようにしたかった)、インストールを気軽にと考えて作ったものだが、結果的にC拡張部分がない mruby-pure-regexp よりもビルド時間・バイナリサイズとも若干小さくなった。
  • 実行速度だけで見るとOnigmoがとんでもなく高速なので、引き続き普通のmrubyアプリケーションでは最も使われる選択肢になるのは間違いなさそう。
  • posix regexpなので、 「いつものRuby正規表現」はことごとく使えないと考えた方がいい と思う。例えば \A \z \d などは使えない。それで構わない人が使うことになる。
    • たとえばLinuxで使えるGNU regexpがどの記法をサポートするか、は この辺 を見るとわかりそう。
    • Mac だとさらに \w も使えないみたいですが... しょうじき差分を把握し切れていません...。

微妙に使いどころがなさそうだが、本当にちょびっと使いたいだけなのにバイナリサイズやビルド時間が増大するのは... というニッチな場面ではいいのかも。

ちなみに、 mruby-optparse が正規表現に依存するという話があり、ちょっとしたツールでOnigmoがバンドルされがちであったが、GNU正規表現である程度動くようにしたフォークを以下に作っている(もっとテストケース増やさないと不安だけど...)。

github.com

まとめ

ニッチな正規表現クラス実装 mgem を作った。

テストケースを足してくれたりする人を歓迎しています。