Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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) を使用した環境で正しく実行できない問題がありました。主な原因は以下の点にありました。

  1. 実行可能ファイルの命名規則の違い: Unix系OSではデフォルトの実行可能ファイル名がa.outとなることが多いですが、Windowsでは.exe拡張子が必要です。
  2. pthreadライブラリの互換性の問題: threadring.cのようなC言語で書かれたベンチマークは、POSIXスレッド(pthread)を使用しています。MinGW環境におけるpthreadの実装は、Unix系OSのそれとは細部で異なり、特にスタックサイズの設定に関するAPIの挙動が問題となっていました。
  3. 外部依存ライブラリの有無: 一部のベンチマーク(例: 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つの側面に分けられます。

  1. 実行可能ファイルの拡張子対応:

    • timing.shスクリプト内で、unameコマンドの出力に基づいてOSを判別し、Windows環境(*MINGW*, *WIN32*, *CYGWIN*)であれば実行可能ファイルの拡張子を.exeに設定するEXE変数を導入しました。
    • これにより、a.outという固定名ではなく、プラットフォームに応じた適切な実行ファイル名(例: a.exe)が使用されるようになります。
  2. 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_setstackaddrpthread_attr_setstacksizeを組み合わせて使用する必要がある場合があります。このコミットでは、__MINGW32__または__MINGW64__が定義されている場合に、pthread_attr_setstackaddrpthread_attr_setstacksizeを使用する条件付きコンパイルを追加し、MinGW環境でのビルドエラーを回避しています。
  3. 依存ライブラリの有無チェックとテストスキップ (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_setstackaddrpthread_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.outa.$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 ... fiif [ $mode = run ] && $haveglib; then ... fiif $havegmp; then ... fiといった条件文が追加されました。
    • これにより、対応する依存ライブラリがシステムに存在しない場合、C言語版のベンチマークはスキップされ、ビルドエラーや実行時エラーを防ぎます。Go言語版のベンチマークは引き続き実行されます。

これらの変更により、Go言語のベンチマークスイートはWindows環境でもより堅牢に、かつ正確に動作するようになりました。

関連リンク

  • Gerrit Change-Id: https://golang.org/cl/100210043

参考にした情報源リンク