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

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

このコミットは、Go言語の標準ライブラリstrconvパッケージにおける整数から文字列への変換処理のパフォーマンス改善に関するものです。特にGOARCH=386アーキテクチャ(32ビットシステム)において、uintptrへの型キャストを導入することで、わずかながら高速化を実現しています。

コミット

commit 6890afd9a34646b20043d0dffe32cabd0f3ec51c
Author: Robert Griesemer <gri@golang.org>
Date:   Wed Dec 14 11:14:10 2011 -0800

    strconv: slightly faster int conversion for GOARCH=386
    
    benchmark                           old ns/op    new ns/op    delta
    strconv_test.BenchmarkFormatInt         12198        12031   -1.37%
    strconv_test.BenchmarkAppendInt          9268         9153   -1.24%
    strconv_test.BenchmarkFormatUint         3538         3429   -3.08%
    strconv_test.BenchmarkAppendUint         3133         3062   -2.27%
    
    No performance difference for GOARCH=amd64.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5488089

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

https://github.com/golang/go/commit/6890afd9a34646b20043d0dffe32cabd0f3ec51c

元コミット内容

strconv: slightly faster int conversion for GOARCH=386

benchmark                           old ns/op    new ns/op    delta
strconv_test.BenchmarkFormatInt         12198        12031   -1.37%
strconv_test.BenchmarkAppendInt          9268         9153   -1.24%
strconv_test.BenchmarkFormatUint         3538         3429   -3.08%
strconv_test.BenchmarkAppendUint         3133         3062   -2.27%

No performance difference for GOARCH=amd64.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5488089

変更の背景

このコミットの背景には、Go言語の標準ライブラリであるstrconvパッケージのパフォーマンス最適化があります。strconvパッケージは、数値と文字列間の変換(例: 整数を文字列に変換するItoa関数など)を提供する非常に基本的なパッケージであり、多くのGoプログラムで頻繁に使用されます。そのため、このパッケージのわずかなパフォーマンス改善でも、全体的なアプリケーションの実行速度に大きな影響を与える可能性があります。

特に、このコミットはGOARCH=386、つまり32ビットアーキテクチャに焦点を当てています。当時のGo言語は様々なアーキテクチャをサポートしており、それぞれのアーキテクチャで最適なパフォーマンスを引き出すための調整が行われていました。32ビットシステムでは、64ビットシステムとは異なるレジスタの利用可能性やデータ型のサイズの違いがパフォーマンスに影響を与えることがあります。

コミットメッセージに示されているベンチマーク結果は、FormatIntAppendIntFormatUintAppendUintといった関数において、1.24%から3.08%の改善が見られたことを示しています。これは、数値から文字列への変換処理において、特定のアーキテクチャでボトルネックとなっていた部分を特定し、それを解消しようとする試みであったと考えられます。

前提知識の解説

1. strconvパッケージ

strconvパッケージは、Go言語の標準ライブラリの一部であり、文字列と基本的なデータ型(ブール値、整数、浮動小数点数)の間で変換を行うための関数を提供します。例えば、strconv.Itoa(i int) stringは整数を文字列に変換し、strconv.Atoi(s string) (int, error)は文字列を整数に変換します。これらの関数は、ログ出力、ユーザー入力の処理、ネットワークプロトコルの実装など、様々な場面で利用されます。

2. uintptr

uintptrはGo言語の組み込み型の一つで、ポインタを保持するのに十分な大きさの符号なし整数型です。そのサイズはシステムに依存し、32ビットシステムでは32ビット、64ビットシステムでは64ビットになります。uintptrは主にunsafeパッケージと組み合わせて、低レベルのメモリ操作やシステムコールを行う際に使用されます。

このコミットでは、uintptrがポインタとしてではなく、数値計算の文脈で型キャストのターゲットとして使用されています。これは、特定のアーキテクチャにおいて、uintptrへの型キャストがコンパイラによる最適化を促し、結果としてより効率的な機械語コードが生成される可能性があるためです。特に、32ビットシステムでは、64ビット整数(uint64)の演算が複数レジスタを必要とする場合があり、uintptr(32ビット)への変換がレジスタの利用効率を改善するケースが考えられます。

3. GOARCH環境変数

GOARCHはGo言語のビルド環境変数の一つで、ターゲットとするCPUアーキテクチャを指定します。例えば、GOARCH=amd64は64ビットIntel/AMDアーキテクチャを、GOARCH=386は32ビットIntel/AMDアーキテクチャを指します。Goコンパイラは、このGOARCHの値に基づいて、ターゲットアーキテクチャに最適化されたバイナリを生成します。このコミットがGOARCH=386に特化したパフォーマンス改善をもたらしているのは、32ビットアーキテクチャ特有の最適化ポイントが存在したためです。

4. ベンチマーク

Go言語には、コードのパフォーマンスを測定するための組み込みのベンチマークツールがあります。go test -bench=.コマンドを実行することで、ベンチマーク関数(Benchmarkプレフィックスを持つ関数)を実行し、操作あたりの時間(ns/op)やメモリ割り当てなどのパフォーマンス指標を測定できます。コミットメッセージに記載されているベンチマーク結果は、このツールによって得られたものです。

技術的詳細

このコミットの技術的な核心は、src/pkg/strconv/itoa.goファイル内のformatBits関数における型キャストの変更です。具体的には、uint64型の変数から計算された値を、digits01digits10digitsといったバイトスライス(または配列)のインデックスとして使用する際に、明示的にuintptr型にキャストしています。

変更前は、これらのインデックス計算の結果は暗黙的にint型として扱われるか、あるいはuint64のまま使用されていました。しかし、32ビットシステム(GOARCH=386)では、uint64の値を直接インデックスとして使用すると、内部的に64ビット演算が必要となり、これがオーバーヘッドとなる可能性がありました。

uintptrは、そのアーキテクチャのポインタサイズに合わせた符号なし整数型であるため、32ビットシステムでは32ビット幅になります。uint64からuintptrへのキャストは、値が32ビットの範囲に収まる限りにおいて、コンパイラがより効率的な32ビット演算命令を生成する機会を提供します。

例えば、j := u - q*100という計算結果は、uuint64であっても、jの値は常に0から99の範囲に収まります。この値は32ビットで表現可能であり、uintptr(j)とキャストすることで、コンパイラは32ビットレジスタを使ったより高速なインデックス計算を行うことができるようになります。

コミットメッセージに「No performance difference for GOARCH=amd64.」とあるのは、64ビットシステム(GOARCH=amd64)ではuint64uintptrのサイズが同じ(64ビット)であるため、この型キャストによるパフォーマンス上のメリットがないことを示しています。これは、この最適化が32ビットアーキテクチャ特有のレジスタ利用や演算効率の改善を狙ったものであることを裏付けています。

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

変更はsrc/pkg/strconv/itoa.goファイル内のformatBits関数に集中しています。

--- a/src/pkg/strconv/itoa.go
+++ b/src/pkg/strconv/itoa.go
@@ -76,7 +76,7 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 		for u >= 100 {
 			i -= 2
 			q := u / 100
-			j := u - q*100
+			j := uintptr(u - q*100)
 			a[i+1] = digits01[j]
 			a[i+0] = digits10[j]
 			u = q
@@ -84,7 +84,7 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 		if u >= 10 {
 			i--
 			q := u / 10
-			a[i] = digits[u-q*10]
+			a[i] = digits[uintptr(u-q*10)]
 			u = q
 		}
 
@@ -103,7 +103,7 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 		b := uint64(base)
 		for u >= b {
 			i--
-			a[i] = digits[u%b]
+			a[i] = digits[uintptr(u%b)]
 			u /= b
 		}
 	}

具体的には、以下の3箇所でuintptr()への型キャストが追加されています。

  1. j := uintptr(u - q*100)
  2. a[i] = digits[uintptr(u-q*10)]
  3. a[i] = digits[uintptr(u%b)]

コアとなるコードの解説

formatBits関数は、符号なし整数uを特定の基数base(例: 10進数、16進数)で文字列に変換し、バイトスライスdstに書き込むための内部ヘルパー関数です。この関数は、数値を下位桁から順に処理し、対応する文字を一時的なバッファaに格納していきます。

変更された行は、いずれも計算された数値(ju-q*10u%b)を、文字のルックアップテーブル(digits01digits10digits)のインデックスとして使用する部分です。

  • j := uintptr(u - q*100): この行は、uが100以上のときに、下2桁の値を計算しています。例えば、uが123の場合、qは1、u - q*100は23となります。この2桁の値をjに格納し、digits01digits10を使って対応する文字('2'と'3')を取得します。ここでjuintptrにキャストすることで、32ビットシステムでのインデックス計算が効率化されます。

  • a[i] = digits[uintptr(u-q*10)]: この行は、uが10以上のときに、下1桁の値を計算しています。例えば、uが12の場合、qは1、u - q*10は2となります。この1桁の値をdigitsテーブルのインデックスとして使用し、対応する文字('2')を取得します。ここでもuintptrへのキャストが適用されています。

  • a[i] = digits[uintptr(u%b)]: この行は、一般的な基数変換のループ内で、現在のubaseで割った余り(つまり、現在の桁の値)を計算しています。この余りの値をdigitsテーブルのインデックスとして使用し、対応する文字を取得します。ここでもuintptrへのキャストが適用されています。

これらの変更は、uint64型の変数から派生した小さな整数値(0-99、0-9など)を配列のインデックスとして使用する際に、明示的にuintptrに型キャストすることで、コンパイラが32ビットアーキテクチャでより効率的なコードを生成できるように促すものです。これにより、ベンチマーク結果に示されるようなわずかながらも測定可能なパフォーマンス改善が実現されました。

関連リンク

参考にした情報源リンク