最初は軽い気持ちで細々とした最適化をしていたんです.
switch を if に変えるとかいう小手先のアレで 10 % も高速化してウケてる
— ボノボ (@susisu2413) 2017年3月13日
インライン化も同時にしてたから 10 % は言い過ぎか、でも高速化はしてる
— ボノボ (@susisu2413) 2017年3月13日
ちなみにどう最適化するかというと V8 のプロファイラを使って適当に遅そうなところに目星をつけて色々試します.
そんなこんなで Parsimmon*1 より妙に遅い原因を探していたら, ap
, left
, right
(Parsec*2 でいうところの <*>
, <*
, *>
) の実装の効率が悪く, これが主な原因であることがわかりました.
アッアッ 30 % 高速化しました
— ボノボ (@susisu2413) 2017年3月13日
GC 半分くらいになっててウケる
— ボノボ (@susisu2413) 2017年3月13日
その後, 比較用の JSON パーサ実装を (Parsimmon のものと同等になるように) 改良した結果がこれです.
倍速になり PEG.js を抜きました. おわり
— ボノボ (@susisu2413) 2017年3月13日
parsimmon とほぼ同等の速度になった
— ボノボ (@susisu2413) 2017年3月13日
parsimmon よりかなり高機能なので完全勝利と言える
— ボノボ (@susisu2413) 2017年3月13日
このあたりで長いこと不明だった諸悪の根源を見つけられてほぼ満足していますが, さらに細々とした最適化を続けました.
parsimmon 超えた
— ボノボ (@susisu2413) 2017年3月13日
たぶん文字列の内部表現の違いで, 文字コードで比較した方が速い場合と, 文字列自体を比較した方が速い場合があって, なるほど~ってなる
— ボノボ (@susisu2413) 2017年3月13日
処理系によりそうな話になってきたのでこのへんで終わり.
目標達成です. お疲れ様でしたhttps://t.co/5WzPU5C7jv pic.twitter.com/xNlGHz9y2P
— ボノボ (@susisu2413) 2017年3月14日
JS パーサコンビネータ, パフォーマンス改善して最強になったので使ってください https://t.co/68nRYZo3mn
— ボノボ (@susisu2413) 2017年3月14日
以上です.
*1:先行の JS のパーサコンビネータライブラリ https://github.com/jneen/parsimmon
*2:Haskell のパーサコンビネータライブラリ https://github.com/aslatter/parsec/ 機能はほぼこれのパクリ