Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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

Ryo Tomidokoro

May 29, 2019
Tweet

More Decks by Ryo Tomidokoro

Other Decks in Technology

Transcript

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

    View Slide

  2. そもそも何の話か?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  6. PCREとは?

    View Slide

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

    View Slide

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

    View Slide

  9. 50's - 形式言語の研究過程でスティーヴン・クリーネが文
    字群の数学的表記を記述
    60's - ケン・トンプソンがQEDエディタに文字列のパター
    ンマッチ方法として導入
    その後 - edエディタや、grepへ同様機能が実装され、正規
    表現として認知されていった。
    ざっくりとした歴史

    View Slide

  10. Basic Regular Expression
    正規表現の種類
    Extended Regular Expression
    GNU Emacs Regular Expression
    sed, awk, grep の正規表現
    | + ? などの表現が追加
    PHPではereg_系の関数で使われる正規表現
    (現在は非推奨)
    \w \b などの特殊文字列表現が使える

    View Slide

  11. 正規表現の種類
    Perl Compatible Regular Expression
    Lazy match (非欲張り量指定子)などの強力で柔
    軟な表現力が加わった
    正規表現におけるデファクトスタンダードのよう
    な存在

    View Slide

  12. 非欲張り量指定子
    Non GreedyとかLazyとか言われる
    hoge
    正規表現は基本欲張
    hoge
    非欲張り量指定子なら
    hoge

    View Slide

  13. で、PCREとは?

    View Slide

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

    View Slide

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

    View Slide

  16. PCRE-JITとは?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  20. PHPとPCRE

    View Slide

  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

    View Slide

  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/

    View Slide

  23. PHPとPCREの関係
    PHPのソースコード内に丸っとPCREのソースコードが同梱さ
    れている。

    View Slide

  24. PHP7.2系

    View Slide

  25. PHP7.3系

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  33. ところで

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  38. PCRE2も同様

    View Slide

  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 が変更になっていた

    View Slide

  40. エラー内容とその対応
    注)良い子は真似しちゃ駄目な対応が含まれます。

    View Slide

  41. 1. PHP7.3系にあげてみる
    2. 複雑な正規表現を改善する
    3. スタックサイズを上げる
    ext/pcre/php_pcre.c
    #define PCRE_JIT_STACK_MAX_SIZE (192 * 1024)
    を書き換えてコンパイル
    PREG_JIT_STACKLIMIT_ERROR

    View Slide

  42. 1. PCREのコンパイルオプションを変える
    ext/pcre/pcre2lib/config.h
    #define LINK_SIZE 2
    これを4とかにする。64K -> 128K までコンパイル済み正
    規表現のサイズが上がる。
    Compilation failed: regular
    expression is too large

    View Slide

  43. まとめ
    PHP7.3系からPCRE2に変更
    PHP7.3系はStackサイズがちょっと大きい
    pcre.jit=0はパフォーマンスが悪い
    最終手段は再コンパイル!

    View Slide