2010年04月30日
GCC の profile mode を試してみる。
GCC 本家のサイトトップに、「January 25, 2010 An experimental profile mode has been added. 」と出ているのが気になります。
これは C++ 標準ライブラリ(主にコンテナ系)の使い方についてアドバイスしてくれる機能で、効率改善に役立つとのことです。さっそく試してみました。
まずは MinGW の GCC バイナリの方に 4.5.0 の正式版が出ていたので、前回と同様にダウンロードして更新しておきます。
C:\MinGW\gcc-4.5>ls *.lzma gcc-c++-4.5.0-1-mingw32-bin.tar.lzma gcc-core-4.5.0-1-mingw32-bin.tar.lzma gmp-5.0.1-1-mingw32-dev.tar.lzma libgcc-4.5.0-1-mingw32-dll-1.tar.lzma libgmp-5.0.1-1-mingw32-dll-10.tar.lzma libgomp-4.5.0-1-mingw32-dll-1.tar.lzma libmpc-0.8.1-1-mingw32-dll-2.tar.lzma libmpfr-2.4.1-1-mingw32-dll-1.tar.lzma libpthread-2.8.0-3-mingw32-dll-2.tar.lzma libssp-4.5.0-1-mingw32-dll-0.tar.lzma libstdc++-4.5.0-1-mingw32-dll-6.tar.lzma mpc-0.8.1-1-mingw32-dev.tar.lzma mpfr-2.4.1-1-mingw32-dev.tar.lzma pthreads-w32-2.8.0-3-mingw32-dev.tar.lzma
今回は、新機能を使うということで、一応 binutils や mingw-runtime なども全て更新しました。
C:\MinGW\gcc-4.5>ls *.gz binutils-2.20.1-2-mingw32-bin.tar.gz mingwrt-3.18-mingw32-dev.tar.gz mingwrt-3.18-mingw32-dll.tar.gz w32api-3.14-mingw32-dev.tar.gz
全てが C:\MinGW\gcc-4.5 をトップにして、bin,share,lib,include,doc,libexec,mingw32 の 7 つのディレクトリの中に揃うように展開します。
このディレクトリの中で完結するので、bin に PATH を張るだけで OK です。
C:\test>path c:\MinGW\gcc-4.5\bin;%path%
C:\test>g++ -v Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=c:/mingw/gcc-4.5/bin/../libexec/gcc/mingw32/4.5.0/lto-wrapper.exe Target: mingw32 コンフィグオプション: ../gcc-4.5.0/configure --enable-languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --enable-version-specific-runtime-libs --disable-werror --build=mingw32 --prefix=/mingw スレッドモデル: win32 gcc version 4.5.0 (GCC)
とりあえずプロファイルモードのマニュアルの例題のプログラムをコンパイルしてみます。(元のプログラムには std:: か、using namespace std;が足りない気がするのですが…)
C:\test>cat foo.cc #include <vector> int main() { std::vector<int> v; for (int k = 0; k < 1024; ++k) v.insert(v.begin(), k); C:\test>g++ -g foo.cc C:\test>a
ひとまず普通にコンパイルと実行ができることを確認しました。
では、プロファイルモードを使ってみます。
C:\test>g++ -g -D_GLIBCXX_PROFILE foo.cc In file included from c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/ profile/impl/profiler_hash_func.h:51:0, from c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/ profile/impl/profiler.h:400, from c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/ profile/base.h:44, from c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/ profile/vector:39, from c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/ vector:77, from foo.cc:1: c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_ trace.h: In function 'void __gnu_profile::__read_cost_factors()': c:\mingw\gcc-4.5\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_ trace.h:559:62: error: 'setenv' was not declared in this scope
setenv が無いと言われてしまったので、とりあえず当該ファイルの setenv("name", "value", 0) 呼び出しを putenv("name=value") に置き換えてみました。
するとコンパイルは通ったもののリンクエラーが出たので -Wl,--enable-auto-import -lpthread を足してみました。どうも pthread がプロファイル機能の内部で使われているようです。
これでも __sync_val_compare_and_swap_4() が無いといわれるので、最終的にここらへんを参考に -march=i486 を付けたところ、無事にコンパイルとリンクができました。(i386 には CAS 命令が無いので、ジェネリックバイナリではダメなようです。)
C:\test>g++ -g -D_GLIBCXX_PROFILE -march=i486 foo.cc -Wl,--enable-auto-import -lpthread
しかし、出来た exe を実行してみると、何やら Win32 例外が発生してしまいます。(SEGV ってるようです。)
まだ MinGW ではあまりこなれていないのでしょうか ?
pthread 周りが怪しいかと思い、試しに -D_GLIBCXX_PROFILE_NO_THREADS を付けてみたところ、-lpthread が無くてもリンクできたので、おそらく thread が関係ないバイナリなはずです。しかし、これでも動きません。
PARTNER-Win32 デバッガでバックトレースを見てみると…
>k a.exe : : 00401160 mainCRTStartup() KERNEL32.pdb: : 7C817077 _BaseProcessStart@4+23() a.exe : : 00401178 mainCRTStartup+18() a.exe : : 004010E2 __mingw_CRTStartup+C2() msvcrt.pdb : : 77BE9EC5 __cexit+F() a.exe : : 004010E2 __mingw_CRTStartup+C2() msvcrt.pdb : : 77BE9EC5 __cexit+F() msvcrt.pdb : : 77BE9E24 __cinit+9A() a.exe :PROFILER_TRACE.H: 486 : 00406BA6 _ZN13__gnu_profile8__reportEv+42() a.exe :PROFILER_VECTOR_SIZE.H: 77 : 00405F92 _ZN13__gnu_profile26__trace_vector_size_reportEP6_iobufRNSt6__norm6vectorINS_14__warning_dataESaIS4_EEE+42() a.exe :PROFILER_TRACE.H: 379 : 00403D9C _ZN13__gnu_profile12__trace_baseINS_21__container_size_infoENS_27__container_size_stack_infoEE7__writeEP6_iobuf+B8() a.exe :PROFILER_CONTAINER_SIZE.H: 212 : 00408098 _ZNK13__gnu_profile21__container_size_info7__writeEP6_iobuf+98() msvcrt.pdb : : 77BF0E46 _fprintf+33() msvcrt.pdb : : 77BF2859 __output+498()
プロファイルの出力のための fprintf の中で何やら死んでいます。
ためしに profiler_trace.h の __trace_vector_size_report() と __trace_vector_to_list_report() をコメントアウトしてみたら、一応実行はできました。(何も libstdcxx-profile.txt に出ませんが…)
/** @brief Final report method, registered with @b atexit. * * This can also be called directly by user code, including signal handlers. * It is protected against deadlocks by the reentrance guard in profiler.h. * However, when called from a signal handler that triggers while within * __gnu_profile (under the guarded zone), no output will be produced. */ inline void __report(void) { __lock(_GLIBCXX_PROFILE_DATA(__global_lock)); __warning_vector_t __warnings; FILE* __raw_file = __open_output_file("raw"); // **** ココと **** __trace_vector_size_report(__raw_file, __warnings); __trace_hashtable_size_report(__raw_file, __warnings); __trace_hash_func_report(__raw_file, __warnings); // **** ココ**** __trace_vector_to_list_report(__raw_file, __warnings); __trace_list_to_slist_report(__raw_file, __warnings); __trace_list_to_vector_report(__raw_file, __warnings); __trace_map_to_unordered_map_report(__raw_file, __warnings); fclose(__raw_file);
とりあえず今日のところはここまでにしておきます。