2014年7月20日日曜日

Boost.Spirit.Karmaのフォーマット出力が異常に早い

Comparing the performance of a sequence of several generatorsを見てBoost.Spirit.Karmaのフォーマット出力が優秀だと知ったのですが、最近のgccとboostだとどうなるかと思って自分のLinux環境でも実行してみました。
(実行環境: boost: 1.54.0, gcc: 4.8.2 コンパイルオプション: -O3, -std=c++1y, CPU: Core i3 4130T)
ソースは上記ページのものにsnprintfも加えたものを実行しました。(最近はセキュルティの観点でsprintfよりsnprintfが推奨されるため)
処理内容は、12345.12345という小数2つから[12345.123 12345.123 ]という文字列(小数点以下3桁、14文字分のスペース)を繰り返し生成するものです。
すると、Spirit.Karmaがsprintfの4倍近く速いことが分かりました。(-O2オプションでもほとんど同じ結果でした。)

sprintf:        1.13721
snprintf:       1.12995
iostreams:      1.39023
format:         1.99459
karma:          0.231521
karma (string): 0.318302
karma (rule):   0.294326

※iostremasはstd::stringstream、formatはboost::formatを指しています。

また、元々のソースでは12345.12345が直に書かれていたので、定数の最適化が行われている可能性を考えて標準入力から数値を与えるようにソースを改変してみましたが、結果はほとんど変わりませんでした。
疑いようもなくSpirit.Karmaが速いです。

input a decimal
12345.12345
input one more decimal
12345.12345
sprintf with args:      1.14024
snprintf with args:     1.12748
iostreams with args:    1.38619
format with args:               2.01176
karma with args:                0.228151
karma (string) with args:       0.314551
karma (rule) with args: 0.293565

なお、数値の桁数が小さい時は差が縮まりました。

input a decimal
1.0
input one more decimal
2.0
sprintf with args:      0.412689
snprintf with args:     0.393523
iostreams with args:    0.640817
format with args:               1.2292
karma with args:                0.263695
karma (string) with args:       0.327404
karma (rule) with args: 0.307239

Boost.Spirit.Karmaはコードが複雑でコンパイル時間も増えるのでカジュアルに使うのには向かないですが、処理速度を求める時には最適なようです。
カジュアルに使う場合は、処理速度は遅いですがsprintf風の記法で型安全でもあるboost::formatが使いやすいですね。
std::stringstreamは、数値を入れる時に余計なバッファを確保するので遅いようです。(boost::formatよりは速いですが。)

ちなみに、int型をstd::string型に変換するのみの場合でもSpirit.Karmaは速いようです。
C++ Convert Int to String Speed
これを見てもうひとつ分かるのは、boost::lexical_castがsprintf以上に速いということです。
カジュアルに数値を文字列に変換するだけなら、boost::lexical_castがベストチョイスになりそうです。
(C++11以降ではstd::to_stringという選択肢もありますが、こちらの処理速度等の詳細は未確認です。)

0 件のコメント:

コメントを投稿