PCREとPCRE-JITとPHP / pcre-pcre-jit-and-php

PCREとPCRE-JITとPHP / pcre-pcre-jit-and-php

PHPのPCREについて、基本的なこと

F04982ad61107b5408ad139966596316?s=128

Ryo Tomidokoro

May 29, 2019
Tweet

Transcript

  1. PCREとPCRE-JITとPHPの話 Ryo Tomidokoro PHP Study 2019/05/29 @hanhan1978

  2. そもそも何の話か?

  3. preg_… の関数群 [引用] PHP PCRE - Manual https://www.php.net/manual/en/book.pcre.php

  4. 正規表現を使っている例

  5. preg系関数群の正規表現の処理で使われている ライブラリ(PCRE)について、特に運用時に気に なる設定とか、パフォーマンスに関係する部分 について話します。 ※書き方とか文法の話はしません。

  6. PCREとは?

  7. Perl Compatible Regular Expression Perl互換正規表現

  8. と言われても、ピンと来ない人が多いと思うの で、とても簡単な正規表現の説明 ※詳しくは英語版wikipediaを読むと分かりやすい。日本語でも大体OK

  9. 50's - 形式言語の研究過程でスティーヴン・クリーネが文 字群の数学的表記を記述 60's - ケン・トンプソンがQEDエディタに文字列のパター ンマッチ方法として導入 その後 -

    edエディタや、grepへ同様機能が実装され、正規 表現として認知されていった。 ざっくりとした歴史
  10. Basic Regular Expression 正規表現の種類 Extended Regular Expression GNU Emacs Regular

    Expression sed, awk, grep の正規表現 | + ? などの表現が追加 PHPではereg_系の関数で使われる正規表現 (現在は非推奨) \w \b などの特殊文字列表現が使える
  11. 正規表現の種類 Perl Compatible Regular Expression Lazy match (非欲張り量指定子)などの強力で柔 軟な表現力が加わった 正規表現におけるデファクトスタンダードのよう

    な存在
  12. 非欲張り量指定子 Non GreedyとかLazyとか言われる <span>hoge</span> 正規表現は基本欲張 <.+> <span>hoge</span> 非欲張り量指定子なら <.+?> <span>hoge</span>

  13. で、PCREとは?

  14. Perl互換正規表現ライブラリのnative実装。 独自のAPIとPOSIX準拠のAPIの両方がある。 BSDライセンスで公開されていて、様々な言語に 取り入れられている。

  15. [引用] https://www.pcre.org/

  16. PCRE-JITとは?

  17. Just In Time Compiler 正規表現のパターンマッチの速度を上げる目的で導入され た正規表現のJITコンパイラ 通常の正規表現実行前に、JIT最適化を行うためCPUに余分 な負荷をかけるが、正規表現マッチングのパフォーマンス が上がる。

  18. 正規表現ライブラリのベンチマーク [引用] 正規表現技術入門 - 新屋良磨、鈴木勇介、高田謙 技術評論社 (p99)

  19. 正規表現の最適化を行う分、プロセッサに余計 な負荷をかけるが、正規表現のパターンマッチ 実行時間を大幅に軽減できる。 特殊な理由が無い限りPCRE-JITの利用が望まし い。

  20. PHPとPCRE

  21. PCREとPCRE-JITの歴史 1997-9-10 ver 0.91 -> PCREのもっとも古いchangelogの日付 . . . 2011-10-21

    ver 8.20 -> PCRE-JITがリリース 2015-1-05 ver 10.00 -> PCRE2がリリース このリリース以降、PCREはバグフィックスのみ。 PCRE-JITもPCRE2-JITとバージョンに合わせた名前に変更 ※重要 PCRE2-JITにおいて、APIに若干の変更がある [引用] https://www.pcre.org/original/changelog.txt
  22. PHPとPCRE-JITの歴史 PCREはPHP4系から存在していたようなので馴れ初めは割愛 [2015-12-03] PHP7のリリース、pcre.jit=1 がデフォルト設定に。 [2017-11-30] PHP7.2 Support for PCRE

    JIT Fast Path -> pcre_jit_exec [2018-12-06] PHP7.3のリリース PCREからPCRE2にライブラリが変更 [引用] https://www.php.net/releases/
  23. PHPとPCREの関係 PHPのソースコード内に丸っとPCREのソースコードが同梱さ れている。

  24. PHP7.2系

  25. PHP7.3系

  26. 実際にベンチマークしてみる

  27. PHP7以降はpcre.jitが有効

  28. pcre.jit最強? 実行時間を考えるとpcre.jitを有効化すべきだが、場合に よっては有効化できない場合がある。 PHP5系において、コンパイル後の正規表現の実行スタック サイズが64Kを超えてしまう場合、pcre.jitでエラーが発生 する。PREG_JIT_STACKLIMIT_ERROR

  29. PREG_JIT_STACKLIMIT_ERRORの解決策として pcre.jit を0に設定するという対策があるがオススメ はしない。 先程みたとおり、jitコンパイラで最適化された正規表 現はとにかく速い。

  30. JIT無効でベンチマークしてみる

  31. pcre2の性能差で7.3系はjit無効化しても多少性能が良い

  32. pcre.jitを無効化する場合は、その代償をよく 考えた上で無効化すること せめてPHP7.3系に上げることで、JIT無効化環境 でもPHP5系よりも速いパフォーマンスを手に入 れることは可能。

  33. ところで

  34. 64Kを突破したくないですか?

  35. JITのStack Sizeはmin 32K [引用] https://www.pcre.org/original/doc/html/pcrejit.html

  36. もう少しよく読むと...

  37. 最大値は任意に指定できる [引用] https://www.pcre.org/original/doc/html/pcrejit.html

  38. PCRE2も同様

  39. Stackサイズ表 PHPバージョン PCRE-JITスタックサイズ 7.0系 32K ~ 64K 7.1系 32K ~

    64K 7.2系 32K ~ 64K 7.3系 32K ~ 192K 7.3系で PCRE_JIT_STACK_MAX_SIZE が変更になっていた
  40. エラー内容とその対応 注)良い子は真似しちゃ駄目な対応が含まれます。

  41. 1. PHP7.3系にあげてみる 2. 複雑な正規表現を改善する 3. スタックサイズを上げる ext/pcre/php_pcre.c #define PCRE_JIT_STACK_MAX_SIZE (192

    * 1024) を書き換えてコンパイル PREG_JIT_STACKLIMIT_ERROR
  42. 1. PCREのコンパイルオプションを変える ext/pcre/pcre2lib/config.h #define LINK_SIZE 2 これを4とかにする。64K -> 128K までコンパイル済み正

    規表現のサイズが上がる。 Compilation failed: regular expression is too large
  43. まとめ PHP7.3系からPCRE2に変更 PHP7.3系はStackサイズがちょっと大きい pcre.jit=0はパフォーマンスが悪い 最終手段は再コンパイル!