ラベル gcc の投稿を表示しています。 すべての投稿を表示
ラベル gcc の投稿を表示しています。 すべての投稿を表示

2011年11月22日火曜日

GCC最適化オプション(-O0, -O1, -O2, -O3, -funroll-loops)

「An Introduction to GCC」に載っていた例を実際に試してみた。

環境は CentOS-6.0 で、

  • 2.6.32-71.29.1.el6.x86_64 GNU/Linux
  • gcc (GCC) 4.4.4 20100726 (Red Hat 4.4.4-13)

やったこと

本に載っていた"test.c"をそのまま使い、-O0, -O1, -O2, -O3, -O3 -funroll-loops の5種類について実行ファイルのサイズとtimeコマンドの結果を求めた。

コンパイルと実行に使ったPerlスクリプトは以下のとおり。

#!/usr/bin/perl
#
# test.pl
#
@a = ('-Wall -O0', '-Wall -O1', '-Wall -O2', '-Wall -O3', '-Wall -O3 -funroll-loops');
for($i=0; $i <= $#a; $i++){
  print("\[$a[$i]\]\n");
  system("gcc $a[$i] test.c && size -B ./a.out && time ./a.out");
  print("\n\n");
}

ここで、実行ファイルのサイズを求めるにあたっては、ls -lではなくGNU Binutilssizeコマンドを使うようにした。sizeコマンドはELFファイルの中のセクションごとにサイズを調べてくれるので、.textセクションのサイズも分かる。すなわち最適化による命令の量の変化がより明らかになる。

結果

# ./test.pl > test.log 2>&1
# cat test.log
[-Wall -O0]
   text    data     bss     dec     hex filename
   1387     492      16    1895     767 ./a.out
sum = 4e+38

real 0m1.677s
user 0m1.263s
sys 0m0.002s


[-Wall -O1]
   text    data     bss     dec     hex filename
   1329     492      16    1837     72d ./a.out
sum = 4e+38

real 0m0.793s
user 0m0.735s
sys 0m0.003s


[-Wall -O2]
   text    data     bss     dec     hex filename
   1369     492      16    1877     755 ./a.out
sum = 4e+38

real 0m0.457s
user 0m0.442s
sys 0m0.005s


[-Wall -O3]
   text    data     bss     dec     hex filename
   1369     492      16    1877     755 ./a.out
sum = 4e+38

real 0m0.456s
user 0m0.444s
sys 0m0.003s


[-Wall -O3 -funroll-loops]
   text    data     bss     dec     hex filename
   1665     492      16    2173     87d ./a.out
sum = 4e+38

real 0m0.503s
user 0m0.493s
sys 0m0.002s

性能がよいのは-O2-O3で、たぶん同じコード。funroll-loopsの最適化は今回の例では逆効果だった。

サイズを最も小さくできたのは-O1

補足:-Osオプション

-Osオプションを使うとサイズの最適化を行うことができる。これも試した結果、確かにサイズが最も小さくなった。

[-Wall -Os]
   text    data     bss     dec     hex filename
   1289     492      16    1797     705 ./a.out
sum = 4e+38

real 0m0.575s
user 0m0.544s
sys 0m0.003s

-Wall -O1の場合と比較すると、.textセクションのサイズは40バイト減り、実行時間も0.2sくらい減っている。

2011年11月14日月曜日

GCC でコンパイルの中間ファイルを残す

-save-temps というオプションを使う。

例: プリプロセッサの出力を調べる

マクロ "NUM" を含むソース dtestval.c
#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("Value of NUM is %d\n", NUM);
  return 0;
}
-save-tempsオプションとマクロ定義を与えてコンパイルしてみる
$ gcc -save-temps -DNUM="1 + 1" dtestval.c -o dtestval
$ ls -1 dtestval*
dtestval
dtestval.c
dtestval.i
dtestval.o
dtestval.s
プリプロセスの出力ファイル dtestval.i
# 1 "dtestval.c"
# 1 ""
(省略)
# 938 "/usr/include/stdio.h" 3 4

# 2 "dtestval.c" 2

int main(int argc, char *argv[])
{
  printf("Value of NUM is %d\n", 1 + 1);
  return 0;
}
"NUM" の定義が反映されて 1 + 1 になっているのが分かる。

2011年11月13日日曜日

GDB で core を作りつつプロセスを止める

生きているプロセスのプロセスIDを調べて、GDB をそのIDに attach してから kill(GDBの kill コマンド)すると core が出てくれる(もちろんプロセスの executable file はGCCの"-g"オプション付きでコンパイルされている必要がある)。

別の言葉で言うと、シェルから kill -QUIT pid する以外にも方法がある、ということ。