Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Xpressive と Spirit の実行速度

タグ: C++ Boost

Boost.XpressiveBoost.Spirit
似た文法を持つこの2つ、どちらを使うべきかよく迷うので、一つの判断基準として実行速度を比べてみることにした。

使用する Boost は trunk のリビジョン43351。
処理の内容は「ドット区切りのDMS文字列を実数値にする」というもので、ついでに「0?360°のみ」「分の値は0?59」「秒は整数部を0?59で表記し、必要が有れば小数点以下を10進法で記しても良い」などの条件を付ける。
ソースとなるDMS文字列は「0?360°」「360°」「360°?」から1つずつ選択。
その文字列1つにつき

  • Xpressive ( regex 使い捨て)
  • Xpressive ( regex 使い回し)
  • Spirit ( grammar 使い捨て)
  • Spirit ( grammar 使い回し)

の4パターンの処理に掛かる時間を計測する。

#include <boost/xpressive/xpressive_static.hpp>
#include <boost/xpressive/regex_actions.hpp>
#include <boost/spirit.hpp>
#include <boost/spirit/dynamic/switch.hpp>
#include <boost/timer.hpp>

template <typename Iterator>
inline boost::xpressive::basic_regex<Iterator>
make_xpressive_parser(double& result)
{
	using namespace boost::xpressive;

	return
		(
			"360." >>
			repeat<1, 2>('0') >> '.' >>
			repeat<1, 2>('0') >> !('.' >> +as_xpr('0'))
		)[ref(result) = 360.0] |
		(
			repeat<1, 3>(_d)[check((ref(result) = as<int>(_)) < 360)] >> '.' >>
			(! range('0', '5') >> _d)[ref(result) += as<int>(_) / 60.0] >> '.' >>
			(! range('0', '5') >> _d >> !('.' >> +_d))[ref(result) += as<double>(_) / 3600.0]
		);
}

struct dms_grammar : public boost::spirit::grammar<dms_grammar>
{
	dms_grammar(double& result) :
	m_result(result)
	{
	}

	double& m_result;

	template <typename Scannar>
	struct definition
	{
		boost::spirit::rule<Scannar> expr;

		definition(const dms_grammar& self)
		{
			using namespace boost::spirit;
			using phoenix::arg1;
			using phoenix::var;
			using phoenix::val;
			using phoenix::static_cast_;

			expr =
				(
					"360." >>
					repeat_p(1, 2)[ch_p('0')] >> '.' >>
					repeat_p(1, 2)[ch_p('0')] >> ! ('.' >> +ch_p('0'))
				)[var(self.m_result) = 360.0] |
				(
					(uint_parser<unsigned int, 10, 1, 3>())[var(self.m_result) = arg1] >>
					switch_p(val(self.m_result) < 360)
					[
						case_p<true>(ch_p('.')),
						case_p<false>(nothing_p)
					] >>
					eps_p
					(
						((range_p('0', '5') >> digit_p) | digit_p) >> '.'
					) >> uint_p[var(self.m_result) += static_cast_<double>(arg1) / 60.0] >> '.' >>
					eps_p
					(
						((range_p('0', '5') >> digit_p) | digit_p) >> ! ('.' >> +digit_p)
					) >> ureal_p[var(self.m_result) += arg1 / 3600.0]
				);
		}

		const boost::spirit::rule<Scannar>& start() const
		{
			return expr;
		}	
	};
};

void test(const char* str)
{
	const int roop = 100000;
	double degree;

	std::cout << "[" << str << "]" << std::endl;

	{
		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			regex_match(str, make_xpressive_parser<const char*>(degree));
		}
		std::cout << "xpressive 1: " << t.elapsed() << " s" << std::endl;
	}

	{
		const boost::xpressive::basic_regex<const char*>
			regex(make_xpressive_parser<const char*>(degree));

		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			regex_match(str, regex);
		}
		std::cout << "xpressive 2: " << t.elapsed() << " s" << std::endl;
	}

	{
		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			parse(str, dms_grammar(degree));
		}
		std::cout << "spirit 1: " << t.elapsed() << " s" << std::endl;
	}


	{
		const dms_grammar grammar(degree);

		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			parse(str, grammar);
		}
		std::cout << "spirit 2: " << t.elapsed() << " s" << std::endl;
	}
}

int main(int argc, char* argv[])
{
	test("123.45.6.7");
	test("360.0.0.0");
	test("361.0.1.2");
	return 0;
}

厳密にテストしたわけではないので、期待通りの実装になっているか分からないが、とりあえず気にしない。

これを Windows XP + Pentium4 3.6GHz + VS2005 でリリースビルドした結果がこれ。

[123.45.6.7]
xpressive 1: 4.203 s
xpressive 2: 2.421 s
spirit 1: 0.344 s
spirit 2: 0.094 s
[360.0.0.0]
xpressive 1: 2.125 s
xpressive 2: 0.328 s
spirit 1: 0.25 s
spirit 2: 0.016 s
[361.0.1.2]
xpressive 1: 3.844 s
xpressive 2: 1.891 s
spirit 1: 0.281 s
spirit 2: 0.031 s

Mac OS X 10.5.2 + Core Duo 2.0GHz + gcc4.0.1 で -O3 ビルドした結果はこう。

[123.45.6.7]
xpressive 1: 3.80625 s
xpressive 2: 1.30441 s
spirit 1: 0.29001 s
spirit 2: 0.06282 s
[360.0.0.0]
xpressive 1: 2.55803 s
xpressive 2: 0.189298 s
spirit 1: 0.246766 s
spirit 2: 0.019943 s
[361.0.1.2]
xpressive 1: 3.25801 s
xpressive 2: 0.742447 s
spirit 1: 0.24665 s
spirit 2: 0.020515 s

見ての通り、速度的には Spirit の方が速い。
しかし書きやすさという点では Xpressive の方が上。
その辺は後発で、しかもちゃんとした正規表現なだけはある。

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/70-257b7cab
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。