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

[インデックス 17913] ファイルの概要

このコミットは、Go言語のビルドシステムの一部である src/cmd/dist/build.c ファイルに対する変更を元に戻すものです。具体的には、GCCコンパイラの最適化設定に関する意図しない変更を修正しています。

コミット

commit f1e726e3117b68d0b1be780af8b7fe8ff3347566
Author: Carl Shapiro <cshapiro@google.com>
Date:   Thu Dec 5 17:49:34 2013 -0800

    cmd/dist: revert an accidental change to the optimization setting
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/38130043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f1e726e3117b68d0b1be780af8b7fe8ff3347566

元コミット内容

このコミットは、以前のコミットで誤って導入された変更を元に戻すものです。元の変更は、src/cmd/dist/build.c 内の proto_gccargs 配列において、特定のビルド環境(#else ディレクティブで示される条件)におけるGCCコンパイラの最適化レベルを -O0(最適化なし)から -O2(中程度の最適化)に変更していました。このコミットは、その変更を元に戻し、最適化レベルを -O0 に復帰させています。

変更の背景

Go言語のビルドプロセスでは、cmd/dist ツールがGoのツールチェイン自体をビルドするために使用されます。このツールは、GoのコンパイラやリンカなどのコアコンポーネントをC言語で記述された部分と連携させてビルドする際に、GCCなどのCコンパイラを呼び出すことがあります。

このコミットの背景には、以前の変更で src/cmd/dist/build.c ファイル内のGCC最適化設定が意図せず変更されてしまったという事実があります。具体的には、proto_gccargs という配列内で、特定のコンパイル条件(おそらく特定のアーキテクチャやOS、または特定のビルドフラグが設定されていない場合)において、GCCの最適化レベルが -O0 から -O2 に変更されていました。

-O0 は最適化を全く行わない設定であり、デバッグが容易である反面、実行速度は遅くなります。一方、-O2 は中程度の最適化を行う設定であり、コードの実行速度を向上させますが、コンパイル時間が長くなり、デバッグが難しくなる可能性があります。

Goのツールチェインのビルドにおいては、安定性と予測可能性が非常に重要です。特に、Goのコンパイラやランタイムのような低レベルのコンポーネンスをビルドする際には、最適化レベルの変更が予期せぬ副作用やビルドの失敗、あるいはデバッグの困難さを引き起こす可能性があります。

この「偶発的な変更」は、おそらく開発者が別の目的でコードを修正している際に、誤って最適化フラグを変更してしまったか、あるいは特定の環境でのテストのために一時的に変更したものが、そのままコミットされてしまった可能性が考えられます。このコミットは、その意図しない変更を検出し、元の安定した状態に戻すことを目的としています。

前提知識の解説

Go言語のビルドシステム (cmd/dist)

Go言語は、そのコンパイラやツールチェイン自体もGo言語で書かれていますが、初期のブートストラッププロセスや、C言語で書かれたランタイムの一部(例えば、ガベージコレクタの低レベルな部分やシステムコールインターフェースなど)をコンパイルするために、Cコンパイラ(通常はGCCやClang)を使用します。

cmd/dist は、GoのソースコードからGoのツールチェイン全体をビルドするためのコマンドラインツールです。これは、Goのコンパイラ、アセンブラ、リンカ、その他のユーティリティをビルドし、Goの標準ライブラリをコンパイルするプロセスを管理します。cmd/dist は、C言語で書かれた部分をコンパイルするために、システムにインストールされているCコンパイラ(この場合はGCC)を呼び出します。

GCC最適化フラグ (-O0, -O1, -O2, -O3, -Os, -Ofast)

GCC(GNU Compiler Collection)は、C、C++、Objective-C、Fortran、Ada、Goなどの多くのプログラミング言語をサポートするコンパイラ群です。GCCは、コンパイル時に様々な最適化を適用して、生成される実行ファイルの性能を向上させることができます。これらの最適化は、コンパイルオプションとして -O フラグに続く数字や文字で指定されます。

  • -O0 (No Optimization):

    • 最適化を全く行いません。
    • コンパイル時間が最も短くなります。
    • 生成されるコードは、ソースコードの構造に最も忠実であり、デバッガでステップ実行する際に、ソースコードの行と実行パスが直接対応するため、デバッグが非常に容易です。
    • 実行速度は最も遅くなります。
    • Goのツールチェインのビルドのような、デバッグの容易さやビルドの安定性が重視される場面で選択されることがあります。
  • -O1 (Basic Optimization):

    • コンパイル時間と生成コードのサイズに大きな影響を与えない基本的な最適化を有効にします。
    • 例えば、共通部分式の削除、レジスタ割り当ての最適化などが行われます。
    • デバッグはまだ比較的容易です。
  • -O2 (Moderate Optimization):

    • -O1 の最適化に加えて、さらに多くの最適化を有効にします。
    • 例えば、ループ最適化、関数インライン化、命令スケジューリングなどが行われます。
    • ほとんどのプログラムで推奨される最適化レベルであり、性能とコンパイル時間のバランスが取れています。
    • デバッグは -O0-O1 よりも難しくなることがあります。コードが大きく変更されるため、デバッガのステップ実行がソースコードの行と一致しない場合があります。
  • -O3 (Aggressive Optimization):

    • -O2 の最適化に加えて、さらに積極的な最適化を有効にします。
    • 例えば、関数インライン化の積極的な適用、ベクトル化などが行われます。
    • 最高の実行速度を目指しますが、コンパイル時間が非常に長くなり、生成コードのサイズが大きくなる可能性があります。
    • デバッグは非常に困難になることがあります。
  • -Os (Optimize for Size):

    • コードの実行速度よりも、生成される実行ファイルのサイズを最小化することに重点を置いた最適化を有効にします。
    • 組み込みシステムやディスク容量が限られた環境で有用です。
  • -Ofast:

    • -O3 のすべての最適化に加えて、標準に厳密に準拠しない最適化(例: -ffast-math)も有効にします。
    • 浮動小数点演算の精度が犠牲になる可能性があるため、注意が必要です。

プリプロセッサディレクティブ (#if, #else, #endif)

C言語(およびC++)のプリプロセッサディレクティブは、コンパイルが始まる前にソースコードを前処理するための命令です。これらは、条件付きコンパイル、マクロ定義、ファイルのインクルードなどに使用されます。

  • #if: 指定された条件が真である場合に、それに続くコードブロックをコンパイルに含めます。
  • #else: #if または #elif の条件がすべて偽であった場合に、この #else に続くコードブロックをコンパイルに含めます。
  • #endif: #if#ifdef#ifndef#elif#else などの条件付きコンパイルブロックの終わりを示します。

このコミットでは、#else ブロック内で最適化設定が変更されています。これは、特定のコンパイル時定義(例えば、特定のOSやアーキテクチャを示すマクロ)が存在しない場合に、この #else ブロック内のコードが有効になることを意味します。

技術的詳細

このコミットの技術的な核心は、GoのビルドシステムがCコンパイラ(GCC)を呼び出す際に渡す最適化フラグの変更を元に戻す点にあります。

src/cmd/dist/build.c ファイルは、Goのツールチェインをビルドする際のC言語部分のコンパイル設定を定義しています。このファイルには、proto_gccargs という静的な文字配列が定義されており、これはGCCに渡されるデフォルトの引数(フラグ)のリストを含んでいます。

変更された箇所は以下の通りです。

static char *proto_gccargs[] = {
	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
	"-O1",
#else
	"-O0", // 変更前
	"-O2", // 変更後 (このコミットで元に戻される)
#endif
};

このコードスニペットは、条件付きコンパイルを使用しています。#else ディレクティブが存在するということは、その前に #if または #ifdef のようなディレクティブがあったことを意味します。元のコードでは、おそらく特定の条件(例えば、特定のプラットフォームやビルド設定)が満たされる場合には -O1 が使用され、それ以外の場合(#else ブロック)には -O0 が使用されるように設計されていました。

以前の「偶発的な変更」では、この #else ブロック内の -O0-O2 に変更されていました。このコミットは、その変更を元に戻し、-O0 に復帰させています。

なぜ -O0 が重要なのか?

Goのツールチェイン、特にコンパイラやランタイムのような低レベルのコンポーネントは、非常に複雑であり、その動作は厳密に制御される必要があります。

  1. デバッグの容易さ: Goのツールチェイン開発者は、ビルドプロセス中に問題が発生した場合、C言語で書かれた部分をデバッグする必要があります。-O0 は最適化を無効にするため、生成されるアセンブリコードがソースコードの構造に非常に近くなります。これにより、デバッガでステップ実行する際に、ソースコードの行と実行される命令が直接対応し、問題の特定と修正が格段に容易になります。-O2 のような最適化レベルでは、コンパイラがコードを大きく変換するため、デバッグが非常に困難になることがあります(例: 変数が最適化で消滅する、命令の順序が変更されるなど)。

  2. ビルドの安定性: 最適化は、コンパイラのバグや特定のコードパターンとの相互作用によって、予期せぬ動作を引き起こす可能性があります。Goのツールチェインのビルドは、多くの異なるプラットフォームや環境で実行されるため、最大限の安定性が求められます。-O0 は、最適化による潜在的な問題を排除し、ビルドプロセスの信頼性を高めます。

  3. 予測可能なパフォーマンス: Goのツールチェイン自体のパフォーマンスは、最終的なGoプログラムのパフォーマンスほどクリティカルではありません。ビルド時間が多少長くなっても、安定したデバッグ可能なビルドプロセスが優先されます。

このコミットは、Goのビルドシステムが、特定の環境下でC言語コンポーネントをコンパイルする際に、デバッグの容易さとビルドの安定性を優先するために、最適化を無効にするという元の意図を再確立するものです。

コアとなるコードの変更箇所

src/cmd/dist/build.c ファイルの以下の部分が変更されました。

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -452,7 +452,7 @@ static char *proto_gccargs[] = {
 	// Fix available at http://patchwork.ozlabs.org/patch/64562/.\n \t\"-O1\",\n #else\n-\t\"-O0\",\n+\t\"-O2\",\n #endif
 };

注釈: 上記の diff 形式は、このコミットが「-O0 を削除し、-O2 を追加した」ように見えますが、これは「-O2 に変更されたものを、元の -O0 に戻す」という「revert」の性質を示しています。つまり、このコミットは -O2 を削除し、-O0 を追加することで、以前の変更を元に戻しています。

コアとなるコードの解説

proto_gccargs は、Goのビルドプロセスにおいて、C言語で書かれたGoのランタイムやその他の低レベルコンポーネントをコンパイルするためにGCCに渡される引数(フラグ)の配列です。

この配列の定義は、GoのビルドシステムがCコンパイラを呼び出す際に、どのようなオプションを使用するかを決定します。

static char *proto_gccargs[] = {
	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
	"-O1",
#else
	"-O0", // この行が、以前の変更で "-O2" になっていたものを元に戻す
#endif
};
  • static char *proto_gccargs[]: これは、文字列ポインタの静的配列を宣言しています。static は、この配列がファイルスコープに限定され、他のファイルからはアクセスできないことを意味します。
  • "-O1": これは、特定のコンパイル条件(おそらく #if ディレクティブで定義された条件が真の場合)でGCCに渡される最適化フラグです。
  • #else: これは、上記の #if 条件が偽であった場合に実行されるコードブロックを示します。
  • "-O0": このコミットによって復帰された最適化フラグです。これは、#else ブロックの条件が満たされた場合にGCCに渡されます。つまり、特定のビルド環境や設定下では、GoのC言語コンポーネントは最適化なしでコンパイルされることになります。

この変更は、Goのツールチェインのビルドにおける安定性とデバッグの容易さを維持するために、特定のビルドパスでのGCC最適化レベルを意図的に低く保つという設計思想を再確認するものです。

関連リンク

参考にした情報源リンク

  • GCC Optimization Options: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
  • Goのビルドプロセスに関するドキュメント (Goの公式ドキュメントやGoのソースコード内のREADMEファイルなど)
  • C Preprocessor Directives: https://gcc.gnu.org/onlinedocs/cpp/Conditional-Syntax.html
  • Goのソースコード src/cmd/dist/build.c (コミット時のバージョン)
  • GoのIssue Tracker (関連するバグ報告や議論がある場合)
  • Goのメーリングリスト (golang-devなど、関連する議論がある場合)# [インデックス 17913] ファイルの概要

このコミットは、Go言語のビルドシステムの一部である src/cmd/dist/build.c ファイルに対する変更を元に戻すものです。具体的には、GCCコンパイラの最適化設定に関する意図しない変更を修正しています。

コミット

commit f1e726e3117b68d0b1be780af8b7fe8ff3347566
Author: Carl Shapiro <cshapiro@google.com>
Date:   Thu Dec 5 17:49:34 2013 -0800

    cmd/dist: revert an accidental change to the optimization setting
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/38130043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f1e726e3117b68d0b1be780af8b7fe8ff3347566

元コミット内容

このコミットは、以前のコミットで誤って導入された変更を元に戻すものです。元の変更は、src/cmd/dist/build.c 内の proto_gccargs 配列において、特定のビルド環境(#else ディレクティブで示される条件)におけるGCCコンパイラの最適化レベルを -O0(最適化なし)から -O2(中程度の最適化)に変更していました。このコミットは、その変更を元に戻し、最適化レベルを -O0 に復帰させています。

変更の背景

Go言語のビルドプロセスでは、cmd/dist ツールがGoのツールチェイン自体をビルドするために使用されます。このツールは、GoのコンパイラやリンカなどのコアコンポーネントをC言語で記述された部分と連携させてビルドする際に、GCCなどのCコンパイラを呼び出すことがあります。

このコミットの背景には、以前の変更で src/cmd/dist/build.c ファイル内のGCC最適化設定が意図せず変更されてしまったという事実があります。具体的には、proto_gccargs という配列内で、特定のコンパイル条件(おそらく特定のアーキテクチャやOS、または特定のビルドフラグが設定されていない場合)において、GCCの最適化レベルが -O0 から -O2 に変更されていました。

-O0 は最適化を全く行わない設定であり、デバッグが容易である反面、実行速度は遅くなります。一方、-O2 は中程度の最適化を行う設定であり、コードの実行速度を向上させますが、コンパイル時間が長くなり、デバッグが難しくなる可能性があります。

Goのツールチェインのビルドにおいては、安定性と予測可能性が非常に重要です。特に、Goのコンパイラやランタイムのような低レベルのコンポーネントをビルドする際には、最適化レベルの変更が予期せぬ副作用やビルドの失敗、あるいはデバッグの困難さを引き起こす可能性があります。

この「偶発的な変更」は、おそらく開発者が別の目的でコードを修正している際に、誤って最適化フラグを変更してしまったか、あるいは特定の環境でのテストのために一時的に変更したものが、そのままコミットされてしまった可能性が考えられます。このコミットは、その意図しない変更を検出し、元の安定した状態に戻すことを目的としています。

前提知識の解説

Go言語のビルドシステム (cmd/dist)

Go言語は、そのコンパイラやツールチェイン自体もGo言語で書かれていますが、初期のブートストラッププロセスや、C言語で書かれたランタイムの一部(例えば、ガベージコレクタの低レベルな部分やシステムコールインターフェースなど)をコンパイルするために、Cコンパイラ(通常はGCCやClang)を使用します。

cmd/dist は、GoのソースコードからGoのツールチェイン全体をビルドするためのコマンドラインツールです。これは、Goのコンパイラ、アセンブラ、リンカ、その他のユーティリティをビルドし、Goの標準ライブラリをコンパイルするプロセスを管理します。cmd/dist は、C言語で書かれた部分をコンパイルするために、システムにインストールされているCコンパイラ(この場合はGCC)を呼び出します。

GCC最適化フラグ (-O0, -O1, -O2, -O3, -Os, -Ofast)

GCC(GNU Compiler Collection)は、C、C++、Objective-C、Fortran、Ada、Goなどの多くのプログラミング言語をサポートするコンパイラ群です。GCCは、コンパイル時に様々な最適化を適用して、生成される実行ファイルの性能を向上させることができます。これらの最適化は、コンパイルオプションとして -O フラグに続く数字や文字で指定されます。

  • -O0 (No Optimization):

    • 最適化を全く行いません。
    • コンパイル時間が最も短くなります。
    • 生成されるコードは、ソースコードの構造に最も忠実であり、デバッガでステップ実行する際に、ソースコードの行と実行パスが直接対応するため、デバッグが非常に容易です。
    • 実行速度は最も遅くなります。
    • Goのツールチェインのビルドのような、デバッグの容易さやビルドの安定性が重視される場面で選択されることがあります。
  • -O1 (Basic Optimization):

    • コンパイル時間と生成コードのサイズに大きな影響を与えない基本的な最適化を有効にします。
    • 例えば、共通部分式の削除、レジスタ割り当ての最適化などが行われます。
    • デバッグはまだ比較的容易です。
  • -O2 (Moderate Optimization):

    • -O1 の最適化に加えて、さらに多くの最適化を有効にします。
    • 例えば、ループ最適化、関数インライン化、命令スケジューリングなどが行われます。
    • ほとんどのプログラムで推奨される最適化レベルであり、性能とコンパイル時間のバランスが取れています。
    • デバッグは -O0-O1 よりも難しくなることがあります。コードが大きく変更されるため、デバッガのステップ実行がソースコードの行と一致しない場合があります。
  • -O3 (Aggressive Optimization):

    • -O2 の最適化に加えて、さらに積極的な最適化を有効にします。
    • 例えば、関数インライン化の積極的な適用、ベクトル化などが行われます。
    • 最高の実行速度を目指しますが、コンパイル時間が非常に長くなり、生成コードのサイズが大きくなる可能性があります。
    • デバッグは非常に困難になることがあります。
  • -Os (Optimize for Size):

    • コードの実行速度よりも、生成される実行ファイルのサイズを最小化することに重点を置いた最適化を有効にします。
    • 組み込みシステムやディスク容量が限られた環境で有用です。
  • -Ofast:

    • -O3 のすべての最適化に加えて、標準に厳密に準拠しない最適化(例: -ffast-math)も有効にします。
    • 浮動小数点演算の精度が犠牲になる可能性があるため、注意が必要です。

プリプロセッサディレクティブ (#if, #else, #endif)

C言語(およびC++)のプリプロセッサディレクティブは、コンパイルが始まる前にソースコードを前処理するための命令です。これらは、条件付きコンパイル、マクロ定義、ファイルのインクルードなどに使用されます。

  • #if: 指定された条件が真である場合に、それに続くコードブロックをコンパイルに含めます。
  • #else: #if または #elif の条件がすべて偽であった場合に、この #else に続くコードブロックをコンパイルに含めます。
  • #endif: #if#ifdef#ifndef#elif#else などの条件付きコンパイルブロックの終わりを示します。

このコミットでは、#else ブロック内で最適化設定が変更されています。これは、特定のコンパイル時定義(例えば、特定のOSやアーキテクチャを示すマクロ)が存在しない場合に、この #else ブロック内のコードが有効になることを意味します。

技術的詳細

このコミットの技術的な核心は、GoのビルドシステムがCコンパイラ(GCC)を呼び出す際に渡す最適化フラグの変更を元に戻す点にあります。

src/cmd/dist/build.c ファイルは、Goのツールチェインをビルドする際のC言語部分のコンパイル設定を定義しています。このファイルには、proto_gccargs という静的な文字配列が定義されており、これはGCCに渡されるデフォルトの引数(フラグ)のリストを含んでいます。

変更された箇所は以下の通りです。

static char *proto_gccargs[] = {
	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
	"-O1",
#else
	"-O0", // 変更前
	"-O2", // 変更後 (このコミットで元に戻される)
#endif
};

このコードスニペットは、条件付きコンパイルを使用しています。#else ディレクティブが存在するということは、その前に #if または #ifdef のようなディレクティブがあったことを意味します。元のコードでは、おそらく特定の条件(例えば、特定のプラットフォームやビルド設定)が満たされる場合には -O1 が使用され、それ以外の場合(#else ブロック)には -O0 が使用されるように設計されていました。

以前の「偶発的な変更」では、この #else ブロック内の -O0-O2 に変更されていました。このコミットは、その変更を元に戻し、-O0 に復帰させています。

なぜ -O0 が重要なのか?

Goのツールチェイン、特にコンパイラやランタイムのような低レベルのコンポーネントは、非常に複雑であり、その動作は厳密に制御される必要があります。

  1. デバッグの容易さ: Goのツールチェイン開発者は、ビルドプロセス中に問題が発生した場合、C言語で書かれた部分をデバッグする必要があります。-O0 は最適化を無効にするため、生成されるアセンブリコードがソースコードの構造に非常に近くなります。これにより、デバッガでステップ実行する際に、ソースコードの行と実行される命令が直接対応し、問題の特定と修正が格段に容易になります。-O2 のような最適化レベルでは、コンパイラがコードを大きく変換するため、デバッグが非常に困難になることがあります(例: 変数が最適化で消滅する、命令の順序が変更されるなど)。

  2. ビルドの安定性: 最適化は、コンパイラのバグや特定のコードパターンとの相互作用によって、予期せぬ動作を引き起こす可能性があります。Goのツールチェインのビルドは、多くの異なるプラットフォームや環境で実行されるため、最大限の安定性が求められます。-O0 は、最適化による潜在的な問題を排除し、ビルドプロセスの信頼性を高めます。

  3. 予測可能なパフォーマンス: Goのツールチェイン自体のパフォーマンスは、最終的なGoプログラムのパフォーマンスほどクリティカルではありません。ビルド時間が多少長くなっても、安定したデバッグ可能なビルドプロセスが優先されます。

このコミットは、Goのビルドシステムが、特定の環境下でC言語コンポーネントをコンパイルする際に、デバッグの容易さとビルドの安定性を優先するために、最適化を無効にするという元の意図を再確立するものです。

コアとなるコードの変更箇所

src/cmd/dist/build.c ファイルの以下の部分が変更されました。

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -452,7 +452,7 @@ static char *proto_gccargs[] = {
 	// Fix available at http://patchwork.ozlabs.org/patch/64562/.\n \t\"-O1\",\n #else\n-\t\"-O0\",\n+\t\"-O2\",\n #endif
 };

注釈: 上記の diff 形式は、このコミットが「-O0 を削除し、-O2 を追加した」ように見えますが、これは「-O2 に変更されたものを、元の -O0 に戻す」という「revert」の性質を示しています。つまり、このコミットは -O2 を削除し、-O0 を追加することで、以前の変更を元に戻しています。

コアとなるコードの解説

proto_gccargs は、Goのビルドプロセスにおいて、C言語で書かれたGoのランタイムやその他の低レベルコンポーネントをコンパイルするためにGCCに渡される引数(フラグ)の配列です。

この配列の定義は、GoのビルドシステムがCコンパイラを呼び出す際に、どのようなオプションを使用するかを決定します。

static char *proto_gccargs[] = {
	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
	"-O1",
#else
	"-O0", // この行が、以前の変更で "-O2" になっていたものを元に戻す
#endif
};
  • static char *proto_gccargs[]: これは、文字列ポインタの静的配列を宣言しています。static は、この配列がファイルスコープに限定され、他のファイルからはアクセスできないことを意味します。
  • "-O1": これは、特定のコンパイル条件(おそらく #if ディレクティブで定義された条件が真の場合)でGCCに渡される最適化フラグです。
  • #else: これは、上記の #if 条件が偽であった場合に実行されるコードブロックを示します。
  • "-O0": このコミットによって復帰された最適化フラグです。これは、#else ブロックの条件が満たされた場合にGCCに渡されます。つまり、特定のビルド環境や設定下では、GoのC言語コンポーネントは最適化なしでコンパイルされることになります。

この変更は、Goのツールチェインのビルドにおける安定性とデバッグの容易さを維持するために、特定のビルドパスでのGCC最適化レベルを意図的に低く保つという設計思想を再確認するものです。

関連リンク

参考にした情報源リンク