ページへ戻る

− Links

 印刷 

技術系備忘録​/C++​/最適化小手先テクニック​/VisualStudio2005,2008,2010コンテナ速度比較 のソース :: シンクリッジ

xpwiki:技術系備忘録/C++/最適化小手先テクニック/VisualStudio2005,2008,2010コンテナ速度比較のソース

  
コーディング小手先テクニックとは多少毛色が違うかもですが、なんとなく VisualStudio2008(VC9) の吐き出すコードが、どうにも遅いような気がしたので試してみました。
ちょっと面白い結果だったので、記載してみます。

std::vector (と、ついでに std::list ) を、上からなめるコードで試してみました。
VisualStudio2005sp1 2008sp1 2010 の3種類で比較です。
各コンパイラの条件はすべて同じハズで、
-最適化オプションは
---実行速度優先(/O2)
---インライン関数の展開(/Ob2)
---組み込み関数を使用する(/Oi)
--_SECURE_SCL はデフォルト(有効)です。
--ヘタに最適化されないように、処理はDLLに逃がしてあります。
--boost は 1.42 を使わせて頂いてます。( bind と function のみ使ってます)
--STL は、それぞれのコンパイラの純正付属品です。


で、以下が結果と考察です。

** 結果 [#k5e567be]

|コンテナ|処理|所要時間(ms)|>|>|h
|~|~|vs2005sp|vs2008sp1|vs2010|h
|vector|Vector_For							|1129		|8746		|310	|
|~|Vector_For2								|642		|7334		|312	|
|~|Vector_StdBind2nd						|307		|913		|307	|
|~|Vector_BoostBind							|306		|1267		|308	|
|~|Vector_Tr1Bind							|-			|914		|307	|
|~|Vector_BoostBind_FuncPtr					|901		|3243		|1051	|
|~|Vector_Tr1Bind_FuncPtr					|-			|1653		|1059	|
|~|Vector_BoostFunction_StdBind2nd			|1016		|3938		|1229	|
|~|Vector_Tr1Function_StdBind2nd			|-			|2460		|1137	|
|~|Vector_BoostFunction_BoostBind_FuncPtr	|1523		|6344		|1971	|
|~|Vector_Tr1Function_Tr1Bind_FuncPtr		|-			|3586		|1764	|
|list|List_StdBind2nd						|1793		|4145		|1790	|
|~|List_BoostBind							|1787		|4060		|1787	|
|~|List_Tr1Bind								|-			|3429		|1790	|

*** コード [#p4a788cf]

#region(コード)
#prettify{{
__declspec(dllexport) int WINAPI Vector_For(const std::vector<int> *p,int n)
{
	for(std::vector<int>::const_iterator i=p->begin(); i!=p->end(); ++i){
		if( *i > n ){
			return *i;
		}
	}
	return p->front();
}
 
__declspec(dllexport) int WINAPI Vector_For2(const std::vector<int> *p,int n)
{
	const std::vector<int>::const_iterator iEnd = p->end();
	for(std::vector<int>::const_iterator i=p->begin(); i!=iEnd; ++i){
		if( *i > n ){
			return *i;
		}
	}
	return p->front();
}
 
__declspec(dllexport) int WINAPI Vector_StdBind2nd(const std::vector<int> *p,int n)
{
	return *std::find_if(p->begin(), p->end(), std::bind2nd(std::greater<int>(),n) );
}
 
__declspec(dllexport) int WINAPI Vector_BoostBind(const std::vector<int> *p,int n)
{
	return *std::find_if(p->begin(), p->end(), boost::bind(std::greater<int>(),_1,n) );
}
 
__declspec(dllexport) int WINAPI Vector_BoostBind_FuncPtr(const std::vector<int> *p,int n)
{
	struct F
	{
		inline static bool f(const int &a,const int &b)
			{
				return a > b;
			}
	};
	return *std::find_if(p->begin(), p->end(), boost::bind(&F::f,_1,n) );
}
 
__declspec(dllexport) int WINAPI Vector_BoostFunction_StdBind2nd(const std::vector<int> *p,int n)
{
	return *std::find_if(p->begin(), p->end(),
		boost::function<bool (const int&)>(std::bind2nd(std::greater<int>(),n)));
}
 
__declspec(dllexport) int WINAPI Vector_BoostFunction_BoostBind_FuncPtr(const std::vector<int> *p,int n)
{
	struct F
	{
		inline static bool f(const int &a,const int &b)
			{
				return a > b;
			}
	};
	return *std::find_if(p->begin(), p->end(),
		boost::function<bool (const int&)>(boost::bind(&F::f,_1,n)));
}
 
__declspec(dllexport) int WINAPI Vector_Tr1Bind(const std::vector<int> *p,int n)
{
#if _MSC_VER < 1500
	return p->front();
#else
	return *std::find_if(p->begin(), p->end(), std::tr1::bind(std::greater<int>(),std::tr1::placeholders::_1,n) );
#endif
}
 
__declspec(dllexport) int WINAPI Vector_Tr1Bind_FuncPtr(const std::vector<int> *p,int n)
{
#if _MSC_VER < 1500
	return p->front();
#else
	struct F
	{
		inline static bool f(const int &a,const int &b)
			{
				return a > b;
			}
	};
	return *std::find_if(p->begin(), p->end(), std::tr1::bind(&F::f,std::tr1::placeholders::_1,n) );
#endif
}
 
__declspec(dllexport) int WINAPI Vector_Tr1Function_StdBind2nd(const std::vector<int> *p,int n)
{
#if _MSC_VER < 1500
	return p->front();
#else
	return *std::find_if(p->begin(), p->end(),
		std::tr1::function<bool (const int&)>(std::bind2nd(std::greater<int>(),n)));
#endif
}
 
__declspec(dllexport) int WINAPI Vector_Tr1Function_Tr1Bind_FuncPtr(const std::vector<int> *p,int n)
{
#if _MSC_VER < 1500
	return p->front();
#else
	struct F
	{
		inline static bool f(const int &a,const int &b)
			{
				return a > b;
			}
	};
	return *std::find_if(p->begin(), p->end(),
		std::tr1::function<bool (const int&)>(std::tr1::bind(&F::f,std::tr1::placeholders::_1,n)));
#endif
}
 
__declspec(dllexport) int WINAPI List_StdBind2nd(const std::list<int> *p,int n)
{
	return *std::find_if(p->begin(), p->end(), std::bind2nd(std::greater<int>(),n) );
}
 
__declspec(dllexport) int WINAPI List_BoostBind(const std::list<int> *p,int n)
{
	return *std::find_if(p->begin(), p->end(), boost::bind(std::greater<int>(),_1,n) );
}
 
__declspec(dllexport) int WINAPI List_Tr1Bind(const std::list<int> *p,int n)
{
#if _MSC_VER < 1500
	return p->front();
#else
	return *std::find_if(p->begin(), p->end(), std::tr1::bind(std::greater<int>(),std::tr1::placeholders::_1,n) );
#endif
}
}}
#endregion

** 考察 [#ub4643f6]

-vs2005 2008 2010 をざっくりと比較すると、vs2005 ≒ vs2010 >> vs2008 という感じで、理由はまったくわからんのですが vs2008 はダントツで遅いコードを吐き出すようです。
-tr1 と boost の比較では、tr1 のほうが早いみたいです。vs2010 はそれ程変わらないですが、vs2008 は最大で2倍くらい tr1 版のほうが早いようなので、vs2008 なら積極的に tr1 を使っといたほうがよさげです。(それでも vs2005 vs2010 には遠く及ばないです)
-vs2008sp1 は、最適化オプションの「インライン関数の展開」を「既定値」だと極端に遅くなるようで、ここには記載してませんが、大体2~4倍くらい遅くなりました。vs2008 ではこの設定の変更は必須な感じです。
-bind は、関数ポインタを渡すより、関数オブジェクトを渡しといたほうが早いようです。関数ポインタであっても、インライン展開されて同程度になるんじゃなかろうかと思ってたんですが、今のところそんなことはないみたいです。
#prettify{{
inline bool f(const int &a,const int &b)
{
	return a > b;
}
void func(const std::vector<int> &v,int n)
{
	std::find_if( v.begin(), v.end(), boost::bind(&f,_1,n) );					// 遅し
	std::find_if( v.begin(), v.end(), boost::bind(std::greater<int>(),_1,n) );	// 早し
}
}}
-ind2nd(bind1st) と bind を比較すると、vs2005 と vs2010 はほぼ同じっぽいですが、vs2008 ならば bind2nd(bind1st) のほうが若干早いみたいです。どっちでも書けるときには bind2nd(bind1st) を使っといたほうがよさげです。
-for 文の最適化は、vs2010 が良いみたいです。vs2005 と vs2008 は、終了条件に vector::end() を使うと遅くなるようなので、事前に vector::end() をローカル変数に持たすとかしたほうがよさげです。
#prettify{{
void func(const std::vector<int> &v)
{
	for(std::vector<int>::const_iterator i=v.begin(); i!=v.end(); ++i);		// 遅し

	const std::vector<int>::const_iterator e = v.end();
	for(std::vector<int>::const_iterator i=v.begin(); i!=e; ++i);			// 早し
}
}}
-function をかますとやっぱり遅くなるようです。

** というわけで、まとめとして [#h9d0dca2]

案の定、VisualStudio2008 の吐き出すコードは遅いという感じでした。vs2005 よりかなり遅いっていうのが、ちょっと残念な印象です。
その点、vs2010 は優秀っぽいです。モノによっては 2005 に負けるみたいですが、for の最適化から察するに、複雑なコードで本気を出す燻し銀的な感じかもしれません。
vs2010 は、開発環境としては、重いし、画面崩れまくるし(←僕の手元ではです)で、ちと印象悪いんですが、コンパイラとして見ると良いものかもしれません。

- 最後に補足。
まず、これにつかったベンチマークプログラムが、大量のデータを単純になめるというものです。実用上よくあるコードかというとそうでもないと思いますので、参考程度ということで御願いします。
最適化オプションやコンパイラの得手不得手、さらには、ベンチマークコードのミスということもあるかもしれません。 
ソース一式を添付しますので、もしミスなどあれば是非ともご指摘など頂き度。
&ref(BenchContain);

よろしく御願いいたします。

  

  • 技術系備忘録/C++/最適化小手先テクニック/VisualStudio2005,2008,2010コンテナ速度比較 のバックアップソース(No. All)
    • 現: 2016-04-01 (金) 16:11:44 takatsuka[3]
      • Deleted an attach file: BenchC at 2016-04-01 (金) 16:10:05