[インデックス 13700] ファイルの概要
このコミットは、Go言語のベンチマークスイートであるtest/bench/shootout
内のpidigits
ベンチマークのパフォーマンス改善と、関連するスクリプトのバグ修正に関するものです。特に、package big
におけるアセンブラ最適化がpidigits
ベンチマークの実行速度を大幅に向上させたことが報告されています。
コミット
commit d199c34cf0b9c536ffd0167159fa50be2261935c
Author: Rob Pike <r@golang.org>
Date: Tue Aug 28 15:33:05 2012 -0700
test/bench/shootout: pidigits is much faster
Also fix a bug in the script (s/runonly/run/)
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/6501051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d199c34cf0b9c536ffd0167159fa50be2261935c
元コミット内容
test/bench/shootout: pidigits is much faster
Also fix a bug in the script (s/runonly/run/)
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/6501051
変更の背景
このコミットの背景には、Go言語の標準ライブラリであるpackage big
における性能改善があります。package big
は、任意精度の整数、有理数、浮動小数点数を扱うためのパッケージであり、数値計算を多用するアプリケーションにおいてその性能は非常に重要です。pidigits
ベンチマークは、円周率の桁数を計算するもので、このような任意精度演算の性能を測るのに適しています。
コミットメッセージにある「After some assembler work in package big.」という記述から、package big
の内部でアセンブラレベルの最適化が行われたことが示唆されます。これは、Go言語のランタイムや標準ライブラリにおいて、特定のクリティカルなパスの性能を最大限に引き出すために、Goのアセンブラ(Plan 9アセンブラの派生)を用いて手書きのアセンブリコードが導入されたことを意味します。このような低レベルの最適化は、特に大規模な数値計算において顕著な性能向上をもたらす可能性があります。
また、ベンチマークスクリプト自体のバグ修正も行われています。これは、性能改善が正しく測定・報告されるようにするための、ベンチマーク環境の健全性を保つための変更です。
前提知識の解説
- Go言語の
package big
: Go言語の標準ライブラリの一つで、任意精度の数値(整数、有理数、浮動小数点数)を扱うためのパッケージです。通常のGoの組み込み型(int
,float64
など)では表現できない、非常に大きな数値や高い精度が求められる計算に使用されます。例えば、暗号通貨、科学技術計算、金融アプリケーションなどで利用されます。 - ベンチマーク (Benchmark): ソフトウェアやシステムの性能を測定するためのテストです。特定のタスクを実行し、その完了にかかる時間やリソース消費量を計測することで、性能のボトルネックを特定したり、最適化の効果を評価したりします。
- Shootoutベンチマーク: The Computer Language Benchmarks Game (旧称: The Great Computer Language Shootout) のベンチマークスイートを指します。これは、様々なプログラミング言語間で共通のアルゴリズムを実装し、その性能を比較するためのものです。
pidigits
はその中の一つのベンチマークであり、円周率の桁数を計算することで、主に任意精度演算や文字列操作の性能を評価します。 - アセンブラ (Assembler): アセンブリ言語で書かれたプログラムを機械語に変換するプログラムです。アセンブリ言語は、CPUの命令セットに直接対応する低レベルのプログラミング言語であり、特定の処理を非常に高速に実行するために手書きで記述されることがあります。Go言語では、Plan 9アセンブラの派生が使用されます。
timing.log
: ベンチマークの実行結果(実行時間など)が記録されるログファイルです。このファイルに新しいエントリが追加されることで、性能改善が数値として示されます。timing.sh
: ベンチマークを実行するためのシェルスクリプトです。このスクリプト内で、各ベンチマークの実行コマンドが定義されています。runonly
とrun
: ベンチマークスクリプト内で使用される関数またはコマンドのプレフィックスと考えられます。runonly
は特定のベンチマークのみを実行する、あるいは特定の条件でのみ実行するといった意味合いで使われていた可能性がありますが、このコミットではrun
に修正されており、常に実行されるように変更されたことを示唆しています。
技術的詳細
このコミットの主要な技術的ポイントは、package big
におけるアセンブラ最適化がpidigits
ベンチマークの性能に与えた影響です。
pidigits
ベンチマークは、Spigotアルゴリズムなどを用いて円周率の桁数を計算します。このアルゴリズムは、大きな数値を扱う多倍長整数演算を頻繁に実行します。Go言語のpackage big
は、これらの多倍長整数演算をソフトウェアで実装していますが、特にパフォーマンスが要求される部分では、手書きのアセンブリコードを導入することで、CPUの特定の命令(例:乗算、除算、加算、減算におけるキャリーやボローの処理)を直接利用し、Goのコンパイラが生成するコードよりも効率的な実行パスを実現できます。
コミットメッセージの「After some assembler work in package big.」は、まさにこのアセンブラによる最適化が完了し、その効果がpidigits
ベンチマークに現れたことを示しています。アセンブラによる最適化は、通常、以下のような効果をもたらします。
- 命令レベルの最適化: CPUの特定の命令を最大限に活用し、より少ないクロックサイクルで処理を完了させます。
- レジスタ割り当ての最適化: 頻繁に使用される値をCPUのレジスタに保持することで、メモリへのアクセス回数を減らし、高速化を図ります。
- パイプラインの最適化: CPUの命令パイプラインを効率的に利用し、並列性を高めます。
timing.log
の変更を見ると、pidigits 10000
の実行時間が大幅に短縮されていることがわかります。
- 変更前:
gc pidigits 3.51u 0.00s 3.52r # -6%
- 変更後:
gc pidigits 2.85u 0.02s 2.88r # -22%
3.52r
から2.88r
への短縮は、実時間(real time)で約18%の高速化に相当します。コメントにある-22%
や-21%
は、おそらく以前のベースラインからの相対的な改善率を示していると考えられます。これは、package big
のアセンブラ最適化が、pidigits
のような数値計算ベンチマークにおいて非常に効果的であったことを明確に示しています。
また、timing.sh
の修正は、pidigits
ベンチマークの実行方法に関するものです。runonly
からrun
への変更は、特定の条件でのみ実行されていたベンチマークが、常に実行されるように変更されたことを意味します。これは、ベンチマークの網羅性を高め、性能変化を継続的に追跡できるようにするための修正です。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
test/bench/shootout/timing.log
test/bench/shootout/timing.sh
test/bench/shootout/timing.log
の変更
--- a/test/bench/shootout/timing.log
+++ b/test/bench/shootout/timing.log
@@ -1063,3 +1063,9 @@ pidigits 10000
gc pidigits 3.51u 0.00s 3.52r # -6%
gc_B pidigits 3.51u 0.01s 3.52r # -6%
+# Aug 28, 2012
+# After some assembler work in package big.
+pidigits 10000
+ gc pidigits 2.85u 0.02s 2.88r # -22%
+ gc_B pidigits 2.88u 0.01s 2.90r # -21%
+
この変更は、pidigits 10000
ベンチマークの新しい実行結果をtiming.log
に追加しています。新しい結果は、gc pidigits
とgc_B pidigits
の両方で、以前の結果よりも大幅に高速化されていることを示しています。特に、gc pidigits
の実時間(real time)が3.52r
から2.88r
に短縮され、コメントで-22%
の改善が示されています。これは、package big
におけるアセンブラ最適化の直接的な効果を反映したものです。
test/bench/shootout/timing.sh
の変更
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -176,7 +176,7 @@ meteor() {\
pidigits() {\
runonly echo 'pidigits 10000'
- runonly 'gcc -O2 pidigits.c -lgmp' a.out 10000
+ run 'gcc -O2 pidigits.c -lgmp' a.out 10000
run 'gccgo -O2 pidigits.go' a.out -n 10000
run 'gc pidigits' $O.out -n 10000
run 'gc_B pidigits' $O.out -n 10000
この変更は、pidigits
関数内のgcc
でコンパイルされたC言語版のpidigits
ベンチマークの実行コマンドを修正しています。具体的には、runonly
というプレフィックスがrun
に変更されています。これにより、この特定のベンチマークが常に実行されるようになり、ベンチマークスイート全体の実行時にその性能が適切に測定されるようになります。
コアとなるコードの解説
このコミット自体は、Go言語のコアライブラリのコード変更(package big
のアセンブラコード)を直接含んでいません。代わりに、そのコアライブラリの変更によってもたらされた性能向上を記録し、ベンチマークスクリプトのバグを修正しています。
timing.log
の変更は、単にベンチマーク結果の記録であり、コードの振る舞いを変更するものではありません。しかし、このログエントリは、package big
におけるアセンブラ最適化が成功し、Go言語の数値計算性能が実際に向上したという重要な証拠となります。
timing.sh
の変更は、ベンチマークの実行ロジックを修正しています。runonly
からrun
への変更は、pidigits
ベンチマークのC言語実装が、ベンチマークスイートの実行時に常に含まれるようにすることを意味します。これにより、Go言語の実装との比較がより正確かつ継続的に行えるようになります。この修正は、ベンチマークの信頼性と網羅性を向上させるためのものです。
このコミットの真の「コアとなるコードの変更」は、このコミットの前にpackage big
に対して行われたアセンブラレベルの最適化であり、このコミットはその最適化の効果を測定し、報告する役割を担っています。
関連リンク
- The Computer Language Benchmarks Game: 異なるプログラミング言語の性能を比較するためのベンチマークスイート。
pidigits
ベンチマークもここに含まれます。 - Go言語の
package big
ドキュメント: - Go言語のアセンブリ: Go言語でアセンブリコードを書く方法に関する情報。
参考にした情報源リンク
- コミットメッセージと差分情報:
- Go言語の公式ドキュメント(
package big
、アセンブリなど) - The Computer Language Benchmarks Gameのウェブサイト
- 一般的なプログラミング言語のベンチマークと最適化に関する知識
- 多倍長整数演算アルゴリズムに関する情報(例:Spigotアルゴリズム)
- Go言語の内部実装に関するコミュニティの議論やブログ記事(具体的なURLは特定できないが、一般的な知識として参照)