ATLやMFCで使われるCStringとWTLで使われるCStringのパフォーマンスを比較してみようかと(ATLはVisual Studio 2008のもの、WTLはWTL 8.0のもの)。
比較は、Releaseビルド(スタティック ライブラリで MFC を使用する、ATL を使用しない、デバッグ無効、最大限の最適化、実行速度を優先、C++の例外なし、ランタイム型情報なしなど)で、pgomgrとRdTscを用いて調べた命令数をみてみた。
コンストラクタ・デストラクタ
単にコンストラクタとデストラクタの命令数を比較するために下のようなコードでみてみた。
1 2 |
ATL::CString strATL; WTL::CString strWTL; |
pgomgrでATL::CStringの場合、CSimpleStringT::CSimpleStringT・CStringT::CStringT・CSimpleStringT::~CSimpleStringT・CStringData::Release・CStringT::~CStringTを使用し命令数は足して31、WTL::CStringの場合、CString::~CStringを使用し命令数は4であった。
RdTscを使って1024*1024回での平均をとるとATL::CStringは43、WTL::CStringは4になった。コンストラクタとデストラクタだけではWTLの方がはるかに軽いようだ。
代入
短い文章(13文字)を代入してみた。
1 2 3 4 5 |
ATL::CString strATL; strATL = _T( "Hello, world!" ); WTL::CString strWTL; strWTL = _T( "Hello, world!" ); |
pgomgrでATL::CStringの場合(コンストラクタ、デストラクタ含めて)命令数は195、WTL::CStringの場合命令数は121であった。RdTscを使って1024*1024回での平均をとるとATL::CStringは530、WTL::CStringは482になった。ここでもWTLの方が軽いようだ。
次に長めの文章(1300文字)を代入してみた。
1 2 |
ATL::CString str; str = _T( "Hello, world!Hello, world!..... |
pgomgrでATL::CStringの場合命令数は195、WTL::CStringの場合命令数は87。RdTscを使って1024*1024回での平均をとるとATL::CStringは1500、WTL::CStringは4128になった。長い文字列の場合ATLの方が軽いようだ。
さて、ここらへんの速度の違いであるが、ソースをみた感じではATLではHeapAllocでメモリを2624バイト確保しmemcpy_sでコピーしているが、WTLではnewでメモリを2614バイト確保しmemcpyでコピーしているところの差なのかもしれない。が、ちなみにGetBuffer( 1300 )での比較をしてみるとATLは728、WTLは672となりWTLの方が速い。さて、どこに違いがあるのかよく見てみるとATL::CStringでは文字列の長さを取得するときにwcslenを使ってるに対しWTLではlstrlenを使ってるようでここでどうやら速度差がでているようであった。ここでなぜ速度差が出たかについてだが、wcslenはwcslen.cというファイルがあるようにソースコードがあるためにコンパイル時に最適化がかかった可能性がある。ためしに、ポインタを渡すようソースを変更すると
1 2 3 |
TCHAR p[] = _T( "Hello, world!Hello, world!..... ATL::CString str; str = p; |
RdTscを使って1024*1024回での平均をとるとATL::CStringは4125、WTL::CStringは4128になった。ということで、長い時には実際には対した変わらないことが分かる。
ちなみに、文字列の長さを与えてあげた場合
1 2 3 |
TCHAR p[] = _T( "Hello, world!Hello, world!..... ATL::CString str; str = ATL::CString( p, 1300 ); |
RdTscを使って1024*1024回での平均をとるとATL::CStringは1423、WTL::CStringは1390になった。
フォーマット
その他良く使うものとしてはフォーマットがあるこれを比較してみようかと。
1 2 |
ATL::CString str; str.Format( _T( "%d%f\r\n" ), 0, 0.0 ); |
pgomgrでATL::CStringの場合命令数は173、WTL::CStringの場合命令数は437。R
RdTscを使って1024*1024回での平均をとるとATL::CStringは5735、WTL::CStringは7505になった。ATLの方が速いようだ。ATLではvswprintf_sを使ってるのに対しWTLでは独自のパースルーチンになっている。
結合
1 2 3 4 5 6 7 |
ATL::CString str1; ATL::CString str2 = _T( "Hello, world!" ); for( int n = 0; n < 1024 * 1024; n++ ) { str1 += str2; } |
このような感じで結合したところ、RdTscを使って平均をとるとATL::CStringは217、WTL::CStringは4550になった。これについては、ATLの方が高速である。
という感じでさほどパフォーマンスは変わらないとみていいのではないかと思う。無難にATL::CStringを選択しても問題ないかと。