[インデックス 19311] ファイルの概要
本コミットは、Go言語のベンチマークスイートであるtest/bench/shootout
ディレクトリ内のテストがWindows環境(特にMinGW)で適切に動作するようにするための修正を含んでいます。具体的には、実行可能ファイルの拡張子の修正、pthread関連のビルドエラーの解決、および依存ライブラリが不足している場合のテストスキップ機能の追加が行われました。
コミット
- Author: ChaiShushan chaishushan@gmail.com
- Date: Fri May 9 14:34:50 2014 -0700
- Commit Hash: aed9762638b9b619b6239367c9368bfa79096cf0
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aed9762638b9b619b6239367c9368bfa79096cf0
元コミット内容
test/bench/shootout: support windows
1. fix executable extension (a.out -> a.exe).
2. fix pthread build error on mingw
3. if depends lib messing, skip the test
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/100210043
変更の背景
Go言語のプロジェクトでは、様々なプラットフォームでの互換性とパフォーマンスが重視されています。test/bench/shootout
は、The Computer Language Benchmarks Game (CLBG) のベンチマークをGo言語で実装し、他の言語とのパフォーマンス比較を行うためのテストスイートです。
このコミット以前は、これらのベンチマークテストがWindows環境、特にMinGW (Minimalist GNU for Windows) を使用した環境で正しく実行できない問題がありました。主な原因は以下の点にありました。
- 実行可能ファイルの命名規則の違い: Unix系OSではデフォルトの実行可能ファイル名が
a.out
となることが多いですが、Windowsでは.exe
拡張子が必要です。 - pthreadライブラリの互換性の問題:
threadring.c
のようなC言語で書かれたベンチマークは、POSIXスレッド(pthread)を使用しています。MinGW環境におけるpthreadの実装は、Unix系OSのそれとは細部で異なり、特にスタックサイズの設定に関するAPIの挙動が問題となっていました。 - 外部依存ライブラリの有無: 一部のベンチマーク(例:
regex-dna
,k-nucleotide
,pidigits
)は、PCRE (Perl Compatible Regular Expressions)、GLib、GMP (GNU Multiple Precision Arithmetic Library) といった外部ライブラリに依存しています。これらのライブラリがWindows環境にインストールされていない場合、ビルドエラーや実行時エラーが発生し、テストスイート全体が中断してしまう可能性がありました。
これらの問題を解決し、Windows環境でもベンチマークテストを安定して実行できるようにするために、本コミットが導入されました。
前提知識の解説
Go言語
Googleによって開発されたオープンソースのプログラミング言語です。静的型付け、コンパイル型言語でありながら、ガベージコレクション、並行処理のためのGoルーチンとチャネルといった現代的な機能を提供します。システムプログラミング、Webサービス、CLIツールなど幅広い分野で利用されています。
ベンチマーク (Benchmark)
ソフトウェアやシステムの性能を測定し、評価するためのテストです。特定のタスクを実行するのにかかる時間、リソース使用量などを計測し、最適化の余地や異なる実装間の性能差を特定するのに役立ちます。
The Computer Language Benchmarks Game (CLBG)
異なるプログラミング言語で同じアルゴリズムを実装し、その実行速度、メモリ使用量、コードサイズなどを比較するプロジェクトです。本コミットで修正対象となっているshootout
ディレクトリは、このCLBGのベンチマークをGo言語で実装したものです。
MinGW (Minimalist GNU for Windows)
Windows上でGNU開発ツール(GCC, G++, makeなど)を使用するための環境を提供するツールセットです。これにより、Unix系OS向けに書かれたC/C++コードをWindows上でコンパイル・実行することが容易になります。
pthread (POSIX Threads)
POSIXスレッドは、Unix系OSにおけるスレッドAPIの標準です。マルチスレッドプログラミングにおいて、スレッドの生成、同期、終了などを制御するための関数群を提供します。Windows環境では、MinGWのようなツールを通じてpthread APIが提供されることがありますが、その実装はネイティブのWindowsスレッドAPIとは異なるため、互換性の問題が生じることがあります。
実行可能ファイルの拡張子 (.exe
vs. a.out
)
- Unix系OS (
a.out
): LinuxやmacOSなどのUnix系OSでは、コンパイラが生成するデフォルトの実行可能ファイル名がa.out
となることが一般的です(もちろん、-o
オプションで変更可能)。これらのシステムでは、ファイル拡張子に特別な意味はなく、実行権限が付与されていれば実行可能です。 - Windows (
.exe
): Windowsでは、実行可能ファイルは通常.exe
という拡張子を持ちます。システムはこの拡張子を見て、そのファイルが実行可能であることを認識します。
pkg-config
pkg-config
は、コンパイル時およびリンク時に必要なライブラリの情報を取得するためのコマンドラインツールです。C/C++プロジェクトで外部ライブラリを使用する際に、ヘッダーファイルのパスやリンクすべきライブラリのパス、名前などを自動的に取得するために利用されます。これにより、Makefileやビルドスクリプトの記述が簡潔になり、クロスプラットフォームでのビルドが容易になります。
技術的詳細
本コミットの技術的詳細は、主に以下の3つの側面に分けられます。
-
実行可能ファイルの拡張子対応:
timing.sh
スクリプト内で、uname
コマンドの出力に基づいてOSを判別し、Windows環境(*MINGW*
,*WIN32*
,*CYGWIN*
)であれば実行可能ファイルの拡張子を.exe
に設定するEXE
変数を導入しました。- これにより、
a.out
という固定名ではなく、プラットフォームに応じた適切な実行ファイル名(例:a.exe
)が使用されるようになります。
-
pthreadビルドエラーの修正 (
threadring.c
):threadring.c
は、複数のスレッドを生成してメッセージをリング状に受け渡すベンチマークです。このベンチマークでは、各スレッドに明示的にスタック領域を割り当てるためにpthread_attr_setstack
関数を使用しています。- MinGW環境では、
PTHREAD_STACK_MIN
マクロが未定義である場合があるため、#ifndef PTHREAD_STACK_MIN
ガードを追加し、もし未定義であればデフォルト値(65535
バイト)を定義するようにしました。 - さらに重要なのは、
pthread_attr_setstack
関数の挙動がMinGWと他のUnix系OSで異なる点です。MinGWでは、pthread_attr_setstack
の代わりにpthread_attr_setstackaddr
とpthread_attr_setstacksize
を組み合わせて使用する必要がある場合があります。このコミットでは、__MINGW32__
または__MINGW64__
が定義されている場合に、pthread_attr_setstackaddr
とpthread_attr_setstacksize
を使用する条件付きコンパイルを追加し、MinGW環境でのビルドエラーを回避しています。
-
依存ライブラリの有無チェックとテストスキップ (
timing.sh
):regex-dna
,k-nucleotide
,pidigits
などのベンチマークは、それぞれPCRE、GLib、GMPといった外部ライブラリに依存しています。timing.sh
スクリプト内で、pkg-config
コマンドを使用してこれらのライブラリがシステムに存在するかどうかをチェックするロジックが追加されました。havepcre
,haveglib
,havegmp
という変数が導入され、pkg-config --cflags <library_name>
が成功するかどうかで真偽が設定されます。- 各ベンチマークの実行部分では、これらの
have
変数の値に基づいて、依存ライブラリが存在する場合のみC言語版のベンチマークを実行するように条件が追加されました。これにより、依存ライブラリがインストールされていない環境でも、テストスイート全体が中断することなく、Go言語版のベンチマークは実行されつつ、C言語版はスキップされるようになります。
コアとなるコードの変更箇所
test/bench/shootout/threadring.c
// PTHREAD_STACK_MIN undeclared on mingw
#ifndef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 65535
#endif
#define THREADS (503)
struct stack {
char x[PTHREAD_STACK_MIN];
@@ -94,7 +98,13 @@ int main(int argc, char **argv)
pthread_mutex_init(mutex + i, NULL);
pthread_mutex_lock(mutex + i);
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ pthread_attr_setstackaddr(&stack_attr, &stacks[i]);
+ pthread_attr_setstacksize(&stack_attr, sizeof(struct stack));
+#else
pthread_attr_setstack(&stack_attr, &stacks[i], sizeof(struct stack));
+#endif
+
pthread_create(&cthread, &stack_attr, thread, (void*)(uintptr_t)i);
}
test/bench/shootout/timing.sh
+EXE="out"
+havepcre=true
+haveglib=true
+havegmp=true
+case "$(uname)" in
+*MINGW* | *WIN32* | *CYGWIN*)\
+\thavepcre=false
+\thaveglib=false
+\thavegmp=false
+\tif which pkg-config >/dev/null 2>&1; then
+\t\tif pkg-config --cflags libpcre >/dev/null 2>&1
+\t\tthen
+\t\t\techo "havepcre"
+\t\t\thavepcre=true
+\t\tfi
+\t\tif pkg-config --cflags glib-2.0 >/dev/null 2>&1
+\t\tthen
+\t\t\thaveglib=true
+\t\tfi
+\t\tif pkg-config --cflags gmp >/dev/null 2>&1
+\t\tthen
+\t\t\thavegmp=true
+\t\tfi
+\tfi
+\tEXE=exe;;\
+esac
# ... (中略) ...
gc() {\
-\t$GC $1.go; $LD $1.$O
+\t$GC $1.go; $LD -o $O.$EXE $1.$O
}
gc_B() {\
-\t$GC -B $1.go; $LD $1.$O
+\t$GC -B $1.go; $LD -o $O.$EXE $1.$O
}
# ... (中略) ...
regexdna() {\
\trunonly gcc -O2 fasta.c
-\trunonly a.out 100000 > x
+\trunonly a.$EXE 100000 > x
\trunonly echo 'regex-dna 100000'
-\trun "gcc $gccm -O2 regex-dna.c -lpcre" a.out <x
+\tif $havepcre; then
+\t\trun "gcc $gccm -O2 regex-dna.c $(pkg-config libpcre --cflags --libs)" a.$EXE <x
+\tfi
# ... (中略) ...
}
# ... (中略) ...
knucleotide() {\
\trunonly gcc -O2 fasta.c
-\trunonly a.out 1000000 > x # should be using 25000000
+\trunonly a.$EXE 1000000 > x # should be using 25000000
\trunonly echo 'k-nucleotide 1000000'
-\tif [ $mode = run ]; then
-\t\trun "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.out <x
+\tif [ $mode = run ] && $haveglib; then
+\t\trun "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.$EXE <x
\tfi
# ... (中略) ...
}
# ... (中略) ...
pidigits() {\
\trunonly echo 'pidigits 10000'
-\trun "gcc $gccm -O2 pidigits.c -lgmp" a.out 10000
+\tif $havegmp; then
+\t\trun "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
+\tfi
# ... (中略) ...
}
# ... (中略) ...
threadring() {\
\trunonly echo 'threadring 50000000'
-\trun "gcc $gccm -O2 threadring.c -lpthread" a.out 50000000
+\trun "gcc $gccm -O2 threadring.c -lpthread" a.$EXE 50000000
# ... (中略) ...
}
chameneos() {\
\trunonly echo 'chameneos 6000000'
-\trun "gcc $gccm -O2 chameneosredux.c -lpthread" a.out 6000000
+\trun "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
# ... (中略) ...
}
コアとなるコードの解説
test/bench/shootout/threadring.c
の変更
PTHREAD_STACK_MIN
の定義: MinGW環境でPTHREAD_STACK_MIN
が未定義の場合に、65535
バイトというデフォルト値を設定しています。これは、pthreadがスレッドスタックに要求する最小サイズであり、この定義がないとコンパイルエラーになる可能性がありました。- 条件付きスタック属性設定:
#if defined(__MINGW32__) || defined(__MINGW64__)
ブロックは、コンパイラがMinGW環境(32ビットまたは64ビット)で動作している場合にのみ有効になります。- このブロック内では、
pthread_attr_setstackaddr
とpthread_attr_setstacksize
を使用してスレッドのスタックアドレスとサイズを設定しています。これは、MinGWのpthread実装が、他のUnix系OSで一般的に使用されるpthread_attr_setstack
とは異なるAPIを要求する場合があるためです。 #else
ブロックでは、MinGW以外の環境(Linuxなど)向けに従来のpthread_attr_setstack
を使用しています。- この変更により、
threadring.c
はMinGW環境でも正しくコンパイルされ、スレッドが適切なスタックサイズで動作するようになります。
test/bench/shootout/timing.sh
の変更
-
EXE
変数の導入とプラットフォーム判定:EXE="out"
でデフォルト値を設定し、case "$(uname)"
で現在のOSを判定しています。*MINGW*
,*WIN32*
,*CYGWIN*
のいずれかにマッチした場合、EXE
変数をexe
に設定します。これにより、Windows環境では実行可能ファイル名が.exe
拡張子を持つようになります。gc()
およびgc_B()
関数(Go言語のコンパイルとリンクを行う関数)内で、生成される実行可能ファイル名に$EXE
を使用するように変更されました(例:$LD -o $O.$EXE $1.$O
)。これにより、Go言語のベンチマークもWindowsの命名規則に従うようになります。- C言語のベンチマーク実行コマンド(例:
fasta
,revcomp
など)でも、a.out
がa.$EXE
に置き換えられ、Windows環境での実行ファイル名が正しく扱われるようになりました。
-
依存ライブラリの有無チェック:
havepcre
,haveglib
,havegmp
というブール変数を導入し、初期値はtrue
に設定されています。- Windows環境(
*MINGW* | *WIN32* | *CYGWIN*
)の場合、これらの変数はまずfalse
に設定されます。 - その後、
pkg-config
コマンドが利用可能であれば(which pkg-config
)、各ライブラリ(libpcre
,glib-2.0
,gmp
)に対してpkg-config --cflags <library_name>
を実行し、成功した場合にそれぞれのhave
変数をtrue
に戻します。これにより、pkg-config
を通じてライブラリの存在が確認されます。
-
条件付きベンチマーク実行:
regexdna
,knucleotide
,pidigits
の各ベンチマークのC言語版実行部分に、if $havepcre; then ... fi
、if [ $mode = run ] && $haveglib; then ... fi
、if $havegmp; then ... fi
といった条件文が追加されました。- これにより、対応する依存ライブラリがシステムに存在しない場合、C言語版のベンチマークはスキップされ、ビルドエラーや実行時エラーを防ぎます。Go言語版のベンチマークは引き続き実行されます。
これらの変更により、Go言語のベンチマークスイートはWindows環境でもより堅牢に、かつ正確に動作するようになりました。
関連リンク
- Gerrit Change-Id:
https://golang.org/cl/100210043
参考にした情報源リンク
- The Computer Language Benchmarks Game: https://benchmarksgame-team.pages.debian.net/benchmarksgame/
- MinGW - Minimalist GNU for Windows: https://www.mingw-w64.org/
- POSIX Threads (pthread): https://en.wikipedia.org/wiki/POSIX_Threads
- pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/
- pthread_attr_setstackaddr (MinGW context): https://sourceforge.net/p/mingw-w64/wiki2/Pthreads/ (General MinGW pthreads info, specific function details might be in headers or docs)
- PTHREAD_STACK_MIN: https://pubs.opengroup.org/onlinepubs/009695399/basedefs/pthread.h.html (POSIX standard for pthread.h)