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

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

このコミットは、Go言語のベンチマークスイートに、浮動小数点演算の性能を測定するための新しいベンチマークとしてマンデルブロ集合の計算を追加するものです。具体的には、test/bench/go1/mandel_test.goという新しいファイルが追加され、マンデルブロ集合を計算するmandelbrot関数と、その性能を測定するためのベンチマーク関数BenchmarkMandelbrot200が実装されています。

コミット

commit cb9759d067289fef850251c9425b56446086e24c
Author: Russ Cox <rsc@golang.org>
Date:   Wed May 30 10:26:59 2012 -0400

    test/bench/go1: add mandelbrot for floating point
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/6244063

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

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

元コミット内容

test/bench/go1: add mandelbrot for floating point

このコミットは、Go言語のベンチマークスイートに、浮動小数点演算の性能を評価するためのマンデルブロ集合計算ベンチマークを追加します。

変更の背景

Go言語の進化において、様々な側面での性能最適化は継続的な課題です。特に浮動小数点演算は、科学技術計算、グラフィックス、機械学習など、多くの分野で重要な役割を果たします。Goのランタイムやコンパイラが浮動小数点演算をどれだけ効率的に処理できるかを正確に測定するためには、代表的なワークロードを用いたベンチマークが必要です。

マンデルブロ集合の計算は、その性質上、大量の浮動小数点演算(加算、乗算、比較など)を必要とします。そのため、CPUの浮動小数点演算ユニット(FPU)の性能や、コンパイラによる浮動小数点演算の最適化能力を評価するのに適したベンチマークとして広く利用されています。このベンチマークの追加は、Go言語が浮動小数点演算を伴うアプリケーションにおいて、競合他言語と比較してどの程度の性能を発揮できるかを把握し、将来的な最適化の方向性を定めるための重要な一歩となります。

前提知識の解説

ベンチマーク (Benchmark)

ベンチマークとは、ソフトウェアやハードウェアの性能を測定し、評価するためのテストのことです。特定のタスクを実行するのにかかる時間やリソース消費量を測定し、異なるシステムや設定間での比較を可能にします。Go言語では、標準のtestingパッケージにベンチマーク機能が組み込まれており、BenchmarkXxxという命名規則に従う関数を記述することで、簡単に性能測定を行うことができます。

浮動小数点演算 (Floating Point Arithmetic)

浮動小数点演算は、非常に大きい数や小さい数を近似的に表現し、計算するための方法です。コンピュータでは、IEEE 754などの標準に基づいて実装されており、科学技術計算やグラフィックス処理など、実数を扱う多くのアプリケーションで不可欠です。浮動小数点演算の性能は、CPUのFPUの設計、コンパイラの最適化、メモリのアクセスパターンなど、様々な要因に影響されます。

マンデルブロ集合 (Mandelbrot Set)

マンデルブロ集合は、複素平面上の点cのうち、漸化式 z_{n+1} = z_n^2 + c (ただし z_0 = 0)で定義される数列 z_n が無限大に発散しないような点の集合です。この集合はフラクタル図形の一種であり、その境界は非常に複雑で美しいパターンを示します。

マンデルブロ集合の計算は、各点cに対して、数列z_nが発散するかどうかを判定するために、一定の繰り返し回数(イテレーション)内で|z_n|が特定の閾値(通常は2.0)を超えるかどうかをチェックします。このプロセスは、複素数の乗算と加算を繰り返し行うため、大量の浮動小数点演算を伴います。

具体的には、複素数 z = Zr + Zi*ic = Cr + Ci*i に対して、z^2(Zr + Zi*i)^2 = Zr^2 - Zi^2 + 2*Zr*Zi*i となります。したがって、漸化式は実部と虚部に分解すると以下のようになります。

  • Zr_{n+1} = Zr_n^2 - Zi_n^2 + Cr
  • Zi_{n+1} = 2*Zr_n*Zi_n + Ci

そして、|z_n|^2 = Zr_n^2 + Zi_n^2 が閾値の二乗(Limit*Limit)を超えるかどうかを判定します。

Go言語のtestingパッケージとベンチマーク

Go言語のtestingパッケージは、ユニットテストだけでなく、ベンチマークテストもサポートしています。ベンチマーク関数はfunc BenchmarkXxx(b *testing.B)というシグネチャを持ち、b.N回ループを実行することで、テスト対象のコードの平均実行時間を測定します。b.Nの値は、ベンチマーク実行時にgo testコマンドによって自動的に調整され、統計的に有意な結果が得られるようにします。

技術的詳細

このコミットで追加されたmandel_test.goファイルは、Go言語のベンチマークフレームワークを利用して、マンデルブロ集合の計算性能を測定します。

mandelbrot関数

mandelbrot(n int) int関数は、n x nのグリッド上でマンデルブロ集合の計算を行います。

  • Iter定数(50)は、各点におけるイテレーションの最大回数を定義します。この回数を超えても発散しない場合は、集合に属するとみなされます。
  • Limit定数(2.0)は、発散を判定するための閾値です。|z_n|がこの値を超えると発散とみなされます。
  • 二重ループでn x nのグリッド上の各点(x, y)を走査します。
  • 各点(x, y)は、複素平面上の点CrCiにマッピングされます。
    • Cr = (2*float64(x)/float64(n) - 1.5)
    • Ci = (2*float64(y)/float64(n) - 1.0) このマッピングにより、マンデルブロ集合の典型的な表示範囲(実部が-2.0から1.0、虚部が-1.5から1.5程度)がカバーされます。
  • 内部ループでは、マンデルブロ集合の漸化式 z_{n+1} = z_n^2 + cIter回まで繰り返します。
    • Zr, Zi は現在のzの実部と虚部。
    • Tr, Ti はそれぞれZr*ZrZi*Ziを保持し、Zr^2 - Zi^2Zr^2 + Zi^2の計算を効率化します。
    • Zi = 2*Zr*Zi + Ci
    • Zr = Tr - Ti + Cr
    • Tr = Zr * Zr
    • Ti = Zi * Zi これらの計算はすべてfloat64型で行われ、大量の浮動小数点演算を発生させます。
  • Tr+Ti <= Limit*Limitという条件は、|z_n|^2 <= Limit^2 と同等であり、z_nが発散していないかをチェックします。
  • イテレーションが終了した後、Tr+Ti <= Limit*Limitであれば、その点はマンデルブロ集合に属するとみなし、okカウンターをインクリメントします。
  • 最終的に、集合に属すると判定された点の総数okを返します。

BenchmarkMandelbrot200関数

BenchmarkMandelbrot200(b *testing.B)関数は、mandelbrot関数をベンチマークするためのGoの標準ベンチマーク関数です。

  • for i := 0; i < b.N; i++ ループ内でmandelbrot(200)を呼び出します。
  • b.Ntestingパッケージによって動的に決定され、mandelbrot(200)の実行時間を統計的に有意な精度で測定するために必要な回数だけ関数が実行されます。
  • mandelbrot(200)は、200x200のグリッドでマンデルブロ集合を計算することを意味し、これにより十分な量の浮動小数点演算が実行され、ベンチマークとして機能します。

このベンチマークは、Go言語の浮動小数点演算の性能、特にfloat64型の計算効率、コンパイラによる最適化、そしてCPUのFPUの利用効率を評価するのに役立ちます。

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

このコミットでは、test/bench/go1/mandel_test.goという新しいファイルが追加されています。

--- /dev/null
+++ b/test/bench/go1/mandel_test.go
@@ -0,0 +1,41 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This benchmark, taken from the shootuot, tests floating point performance.
+
+package go1
+
+import "testing"
+
+func mandelbrot(n int) int {
+	const Iter = 50
+	const Zero float64 = 0
+	const Limit = 2.0
+	ok := 0
+	for y := 0; y < n; y++ {
+		for x := 0; x < n; x++ {
+			Zr, Zi, Tr, Ti := Zero, Zero, Zero, Zero
+			Cr := (2*float64(x)/float64(n) - 1.5)
+			Ci := (2*float64(y)/float64(n) - 1.0)
+
+			for i := 0; i < Iter && (Tr+Ti <= Limit*Limit); i++ {
+				Zi = 2*Zr*Zi + Ci
+				Zr = Tr - Ti + Cr
+				Tr = Zr * Zr
+				Ti = Zi * Zi
+			}
+
+			if Tr+Ti <= Limit*Limit {
+				ok++
+			}
+		}
+	}
+	return ok
+}
+
+func BenchmarkMandelbrot200(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		mandelbrot(200)
+	}
+}

コアとなるコードの解説

追加されたmandel_test.goファイルは、Goのベンチマークテストの慣例に従ってgo1パッケージ内に配置されています。

  1. パッケージ宣言とインポート:

    • package go1: このファイルがgo1パッケージの一部であることを示します。Goのベンチマークは通常、テスト対象のパッケージと同じか、専用のベンチマークパッケージに配置されます。
    • import "testing": Goの標準テストおよびベンチマークフレームワークであるtestingパッケージをインポートします。
  2. mandelbrot関数:

    • この関数は、マンデルブロ集合の計算ロジックをカプセル化しています。
    • nはグリッドのサイズ(n x n)を決定します。
    • Iterは各点の計算における最大イテレーション回数です。
    • Limitは発散判定の閾値です。
    • Zr, Ziは複素数zの実部と虚部を表します。
    • Tr, TiZr*ZrZi*Ziを保持し、計算を最適化します。
    • Cr, Ciは複素数cの実部と虚部を表し、グリッド上の点から導出されます。
    • 内側のループは、マンデルブロ集合の漸化式を繰り返し適用し、zが発散するかどうかをチェックします。
    • Tr+Ti <= Limit*Limitは、|z|^2 <= Limit^2、つまりzがまだ発散していないことを意味します。
    • ok変数は、マンデルブロ集合に属すると判定された点の数をカウントします。
  3. BenchmarkMandelbrot200関数:

    • func BenchmarkMandelbrot200(b *testing.B)というシグネチャは、Goのベンチマーク関数であることを示します。
    • b *testing.Bはベンチマークコンテキストを提供します。
    • for i := 0; i < b.N; i++ループは、ベンチマークの核となる部分です。b.Ngo testコマンドによって自動的に調整され、mandelbrot(200)関数が統計的に有意な回数だけ実行されるようにします。
    • mandelbrot(200)は、200x200のグリッドでマンデルブロ集合を計算し、浮動小数点演算の負荷をかけます。

このコードは、Goのベンチマークのベストプラクティスに従っており、浮動小数点演算の性能を効率的かつ正確に測定するための堅牢な基盤を提供します。

関連リンク

参考にした情報源リンク