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);

とりあえず今日のところはここまでにしておきます。



トラックバックURL

コメントする

名前
URL
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード