[インデックス 14066] ファイルの概要
このコミットは、Go言語のベンチマークスイートである test/bench/shootout
ディレクトリ内の timing.sh
スクリプトに対する変更です。具体的には、Goコンパイラ(8g
または 6g
)のアーキテクチャ(32-bit または 64-bit)に合わせて、GCCコンパイラに渡す -m32
または -m64
オプションを動的に設定するように修正されています。これにより、GoとC/C++のベンチマークが同じアーキテクチャで実行されるようになり、より公平で正確な比較が可能になります。
コミット
commit c4c4b3b46729d8df3a5ee7bd5f0e463290e206da
Author: Russ Cox <rsc@golang.org>
Date: Sun Oct 7 15:49:56 2012 -0400
test/bench/shootout: match gcc architecture to GOARCH
If we're benchmarking 8g, use gcc -m32.
If we're benchmarking 6g, use gcc -m64.
R=golang-dev, bradfitz, minux.ma, remyoudompheng
CC=golang-dev
https://golang.org/cl/6625061
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c4c4b3b46729d8df3a5ee7bd5f0e463290e206da
元コミット内容
test/bench/shootout: match gcc architecture to GOARCH
このコミットの目的は、Goのベンチマークスクリプトにおいて、GCCコンパイラのアーキテクチャをGoコンパイラのアーキテクチャ(GOARCH
)に合わせることです。具体的には、8g
(32-bit Goコンパイラ)を使用している場合はGCCに-m32
オプションを、6g
(64-bit Goコンパイラ)を使用している場合はGCCに-m64
オプションを渡すように変更します。
変更の背景
Go言語のパフォーマンスを評価する際、CやC++などの他の言語と比較ベンチマークを行うことは非常に重要です。test/bench/shootout
ディレクトリは、The Computer Language Benchmarks Game (旧称: The Great Computer Language Shootout) のベンチマークをGo言語で実装し、他の言語の実装と比較するためのものです。
このベンチマークでは、Goで書かれたプログラムと、C/C++で書かれた同等のプログラムの実行時間を比較します。しかし、Goコンパイラが32-bitモード(8g
)で動作しているにもかかわらず、GCCがデフォルトで64-bitバイナリを生成してしまうと、両者の実行環境が異なり、公平な比較ができませんでした。特に、メモリのアライメント、ポインタのサイズ、レジスタの使用方法などが32-bitと64-bitで異なるため、パフォーマンスに影響を与える可能性があります。
このコミットは、このようなアーキテクチャの不一致によるベンチマーク結果の歪みを解消し、より正確で信頼性の高い比較を可能にすることを目的としています。
前提知識の解説
Goコンパイラのアーキテクチャと命名規則
Go言語の初期のコンパイラは、ターゲットアーキテクチャに基づいて命名されていました。
8g
:go tool 8g
は、GOARCH=386
(Intel 32-bit x86) 向けのGoプログラムをコンパイルするためのコンパイラです。6g
:go tool 6g
は、GOARCH=amd64
(Intel 64-bit x86-64) 向けのGoプログラムをコンパイルするためのコンパイラです。5g
:go tool 5g
は、GOARCH=arm
(ARM) 向けのGoプログラムをコンパイルするためのコンパイラです。
これらの命名規則は、Go 1.0リリース以前の時期に広く使われていました。現在のGoでは、go build
コマンドが GOARCH
環境変数に基づいて適切なコンパイラを自動的に選択するため、ユーザーが直接 8g
や 6g
を指定することは稀です。しかし、このコミットが作成された2012年当時は、これらのコンパイラ名がベンチマークスクリプト内で直接参照されることが一般的でした。
GCCコンパイラのアーキテクチャ指定オプション
GCC (GNU Compiler Collection) は、C、C++、Goなど様々なプログラミング言語をコンパイルできるコンパイラ群です。GCCには、生成するバイナリのターゲットアーキテクチャを指定するためのオプションがあります。
-m32
: 32-bit x86アーキテクチャ向けのコードを生成するようGCCに指示します。これにより、32-bitのレジスタ、ポインタサイズ、命令セットが使用されます。-m64
: 64-bit x86-64アーキテクチャ向けのコードを生成するようGCCに指示します。これにより、64-bitのレジスタ、ポインタサイズ、命令セットが使用されます。
これらのオプションは、特にクロスコンパイル環境や、特定のアーキテクチャに最適化されたバイナリを生成したい場合に重要となります。
The Computer Language Benchmarks Game
The Computer Language Benchmarks Game (旧称: The Great Computer Language Shootout) は、様々なプログラミング言語で同じアルゴリズムを実装し、その実行速度、メモリ使用量、コードサイズなどを比較するプロジェクトです。これは、言語のパフォーマンス特性を理解するための貴重な情報源となります。Go言語もこのベンチマークゲームに参加しており、その結果はGoのパフォーマンス改善の指針の一つとなっています。
技術的詳細
このコミットの技術的な核心は、シェルスクリプト timing.sh
内でGoコンパイラの選択(8g
または 6g
)に基づいて、GCCのコンパイルオプションを動的に調整するロジックを追加した点にあります。
スクリプトの冒頭で、GOCHAR
環境変数からGoコンパイラのアーキテクチャを示す文字(8
または 6
)を取得し、それを変数 O
に格納しています。
O=$GOCHAR
GC="go tool ${O}g"
LD="go tool ${O}l"
この O
の値を利用して、GCCに渡すアーキテクチャオプション gccm
を設定する case
文が追加されました。
gccm=""
case "$O" in
8)
gccm=-m32;;
6)
gccm=-m64;;
esac
O
が8
の場合(8g
コンパイラを使用している場合)、gccm
は-m32
に設定されます。O
が6
の場合(6g
コンパイラを使用している場合)、gccm
は-m64
に設定されます。
その後、timing.sh
スクリプト内でC/C++のベンチマークプログラムをコンパイルする際に使用される gcc
コマンドの呼び出し箇所がすべて変更され、新しく定義された gccm
変数が gcc
のオプションとして追加されました。
例えば、fasta
ベンチマークのコンパイル部分では、元の
run 'gcc -O2 fasta.c' a.out 25000000
が、以下のように変更されています。
run "gcc $gccm -O2 fasta.c" a.out 25000000
これにより、gcc
はGoコンパイラと同じアーキテクチャ(32-bitまたは64-bit)でC/C++プログラムをコンパイルするようになります。この変更は、fasta
, reverse-complement
, nbody
, binarytree
, fannkuch
, regexdna
, spectralnorm
, mandelbrot
, meteor
, pidigits
, threadring
, chameneos
など、timing.sh
で実行されるすべてのC/C++ベンチマークに適用されています。
この修正により、GoとC/C++のベンチマークが同じCPUアーキテクチャ(32-bitまたは64-bit)上で実行されることが保証され、より正確なパフォーマンス比較が可能になります。これは、ベンチマーク結果の信頼性を高め、Go言語のパフォーマンス特性をより正確に評価するために不可欠な変更です。
コアとなるコードの変更箇所
変更は test/bench/shootout/timing.sh
ファイルのみです。
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -10,6 +10,14 @@ O=$GOCHAR
GC="go tool ${O}g"
LD="go tool ${O}l"
+gccm=""
+case "$O" in
+8)
+ gccm=-m32;;\n
+6)
+ gccm=-m64;;\n
+esac
+
PATH=.:$PATH
havegccgo=false
@@ -78,7 +86,7 @@ run() {\n
fasta() {\n
runonly echo 'fasta -n 25000000'\n
-\trun 'gcc -O2 fasta.c' a.out 25000000\n
+\trun "gcc $gccm -O2 fasta.c" a.out 25000000\n
\trun 'gccgo -O2 fasta.go' a.out -n 25000000\t#commented out until WriteString is in bufio\n
\trun 'gc fasta' $O.out -n 25000000\n
\trun 'gc_B fasta' $O.out -n 25000000\n
@@ -88,7 +96,7 @@ revcomp() {\n
runonly gcc -O2 fasta.c\n
runonly a.out 25000000 > x\n
runonly echo 'reverse-complement < output-of-fasta-25000000'\n
-\trun 'gcc -O2 reverse-complement.c' a.out < x\n
+\trun "gcc $gccm -O2 reverse-complement.c" a.out < x\n
\trun 'gccgo -O2 reverse-complement.go' a.out < x\n
\trun 'gc reverse-complement' $O.out < x\n
\trun 'gc_B reverse-complement' $O.out < x\n
@@ -97,7 +105,7 @@ revcomp() {\n
nbody() {\n
runonly echo 'nbody -n 50000000'\n
-\trun 'gcc -O2 nbody.c -lm' a.out 50000000\n
+\trun "gcc $gccm -O2 nbody.c -lm" a.out 50000000\n
\trun 'gccgo -O2 nbody.go' a.out -n 50000000\n
\trun 'gc nbody' $O.out -n 50000000\n
\trun 'gc_B nbody' $O.out -n 50000000\n
@@ -105,7 +113,7 @@ nbody() {\n
binarytree() {\n
runonly echo 'binary-tree 15 # too slow to use 20'\n
-\trun 'gcc -O2 binary-tree.c -lm' a.out 15\n
+\trun "gcc $gccm -O2 binary-tree.c -lm" a.out 15\n
\trun 'gccgo -O2 binary-tree.go' a.out -n 15\n
\trun 'gccgo -O2 binary-tree-freelist.go' a.out -n 15\n
\trun 'gc binary-tree' $O.out -n 15\n
@@ -114,7 +122,7 @@ binarytree() {\n
fannkuch() {\n
runonly echo 'fannkuch 12'\n
-\trun 'gcc -O2 fannkuch.c' a.out 12\n
+\trun "gcc $gccm -O2 fannkuch.c" a.out 12\n
\trun 'gccgo -O2 fannkuch.go' a.out -n 12\n
\trun 'gccgo -O2 fannkuch-parallel.go' a.out -n 12\n
\trun 'gc fannkuch' $O.out -n 12\n
@@ -126,7 +134,7 @@ regexdna() {\n
runonly gcc -O2 fasta.c\n
runonly a.out 100000 > x\n
runonly echo 'regex-dna 100000'\n
-\trun 'gcc -O2 regex-dna.c -lpcre' a.out <x\n
+\trun "gcc $gccm -O2 regex-dna.c -lpcre" a.out <x\n
\trun 'gccgo -O2 regex-dna.go' a.out <x\n
\trun 'gccgo -O2 regex-dna-parallel.go' a.out <x\n
\trun 'gc regex-dna' $O.out <x\n
@@ -137,7 +145,7 @@ regexdna() {\n
spectralnorm() {\n
runonly echo 'spectral-norm 5500'\n
-\trun 'gcc -O2 spectral-norm.c -lm' a.out 5500\n
+\trun "gcc $gccm -O2 spectral-norm.c -lm" a.out 5500\n
\trun 'gccgo -O2 spectral-norm.go' a.out -n 5500\n
\trun 'gc spectral-norm' $O.out -n 5500\n
\trun 'gc_B spectral-norm' $O.out -n 5500\n
@@ -160,7 +168,7 @@ knucleotide() {\n
mandelbrot() {\n
runonly echo 'mandelbrot 16000'\n
-\trun 'gcc -O2 mandelbrot.c' a.out 16000\n
+\trun "gcc $gccm -O2 mandelbrot.c" a.out 16000\n
\trun 'gccgo -O2 mandelbrot.go' a.out -n 16000\n
\trun 'gc mandelbrot' $O.out -n 16000\n
\trun 'gc_B mandelbrot' $O.out -n 16000\n
@@ -168,7 +176,7 @@ mandelbrot() {\n
meteor() {\n
runonly echo 'meteor 2098'\n
-\trun 'gcc -O2 meteor-contest.c' a.out 2098\n
+\trun "gcc $gccm -O2 meteor-contest.c" a.out 2098\n
\trun 'gccgo -O2 meteor-contest.go' a.out -n 2098\n
\trun 'gc meteor-contest' $O.out -n 2098\n
\trun 'gc_B meteor-contest' $O.out -n 2098\n
@@ -176,7 +184,7 @@ meteor() {\n
pidigits() {\n
runonly echo 'pidigits 10000'\n
-\trun 'gcc -O2 pidigits.c -lgmp' a.out 10000\n
+\trun "gcc $gccm -O2 pidigits.c -lgmp" a.out 10000\n
\trun 'gccgo -O2 pidigits.go' a.out -n 10000\n
\trun 'gc pidigits' $O.out -n 10000\n
\trun 'gc_B pidigits' $O.out -n 10000\n
@@ -184,14 +192,14 @@ pidigits() {\n
threadring() {\n
runonly echo 'threadring 50000000'\n
-\trun 'gcc -O2 threadring.c -lpthread' a.out 50000000\n
+\trun "gcc $gccm -O2 threadring.c -lpthread" a.out 50000000\n
\trun 'gccgo -O2 threadring.go' a.out -n 50000000\n
\trun 'gc threadring' $O.out -n 50000000\n
}\n
\n chameneos() {\n
runonly echo 'chameneos 6000000'\n
-\trun 'gcc -O2 chameneosredux.c -lpthread' a.out 6000000\n
+\trun "gcc $gccm -O2 chameneosredux.c -lpthread" a.out 6000000\n
\trun 'gccgo -O2 chameneosredux.go' a.out 6000000\n
\trun 'gc chameneosredux' $O.out 6000000\n
}\n
コアとなるコードの解説
このコミットの主要な変更点は、timing.sh
スクリプトの冒頭に gccm
変数を定義し、その値を GOCHAR
に応じて設定する case
文を追加したことです。
-
gccm
変数の導入とcase
文:gccm="" case "$O" in 8) gccm=-m32;; 6) gccm=-m64;; esac
O
変数には、Goコンパイラのアーキテクチャを示す文字(8
または6
)が格納されています。O
が8
の場合(32-bit Goコンパイラ8g
を使用)、gccm
は-m32
に設定されます。O
が6
の場合(64-bit Goコンパイラ6g
を使用)、gccm
は-m64
に設定されます。 このgccm
変数が、GCCコンパイルコマンドに渡すアーキテクチャ指定オプションとなります。
-
gcc
コマンドの変更: スクリプト内のすべてのgcc
コマンドの呼び出し箇所が、以下のように変更されています。- 変更前:
run 'gcc -O2 fasta.c' ...
- 変更後:
run "gcc $gccm -O2 fasta.c" ...
これにより、gcc
コマンドが実行される際に、gccm
変数に格納された-m32
または-m64
オプションが自動的に追加されます。例えば、8g
が使用されている場合はgcc -m32 -O2 fasta.c
となり、6g
が使用されている場合はgcc -m64 -O2 fasta.c
となります。
- 変更前:
この変更により、Go言語のベンチマークとC/C++言語のベンチマークが、常に同じCPUアーキテクチャ(32-bitまたは64-bit)でコンパイルおよび実行されることが保証されます。これにより、ベンチマーク結果の公平性と正確性が大幅に向上し、Go言語のパフォーマンス特性をより信頼性高く評価できるようになります。
関連リンク
- The Computer Language Benchmarks Game: https://benchmarksgame-team.pages.debian.net/benchmarksgame/
- Go言語の公式ウェブサイト: https://golang.org/
- GCC (GNU Compiler Collection) 公式ウェブサイト: https://gcc.gnu.org/
参考にした情報源リンク
- Go言語のコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Go言語のIssue Tracker (Go CL): https://golang.org/cl/6625061 (コミットメッセージに記載されているCLへのリンク)
- GCCのmanページやドキュメント (特に
-m32
,-m64
オプションについて) - Go言語の古いコンパイラに関する情報 (例:
8g
,6g
の役割)