Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

そもそも何の話か?

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

正規表現を使っている例

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

PCREとは?

Slide 7

Slide 7 text

Perl Compatible Regular Expression Perl互換正規表現

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

で、PCREとは?

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

PCRE-JITとは?

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

PHPとPCRE

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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/

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

PHP7.2系

Slide 25

Slide 25 text

PHP7.3系

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

PHP7以降はpcre.jitが有効

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

ところで

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

PCRE2も同様

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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