2017-02-11 10 views
3

ベンチマークコード:行くベンチマークとGC:B /オペアンプのalloc/OP

func BenchmarkSth(b *testing.B) { 
    var x []int 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     x = append(x, i) 
    } 
} 

結果:40 B/opが来たの

  • BenchmarkSth-4 50000000 20.7 ns/op 40 B/op 0 allocs/op 
    

    質問/ sのから? (何らかのトレース+命令をいただければ幸いです)

  • 0のallocを持つうちに40のB/opを持つことはどうですか?
  • どれがGCに影響を与えますか? (B/opまたはallocs/op)
  • 実際には、追加を使ってB/opを0にすることは可能ですか?

答えて

3

The Go Programming Language Specification

Appending to and copying slices

可変引数関数アペンドはまた、スライスタイプでなければならない タイプSのS、ゼロ以上の値xを追加し、得られたスライスを返し、

append(s S, x ...T) S // T is the element type of S 

sの容量が十分でない場合 appendは、既存のスライス要素と追加値の両方に合わせて、十分に大きな新しい基本配列を割り当てます( )。それ以外の場合は、 を追加して、基になる配列を再利用します。

たとえば、操作あたり平均で[40,41]バイトが割り当てられ、必要に応じてスライスの容量が増えます。容量は、償却された一定時間アルゴリズムを使用して増加されます。最大len 1024まで増加させて2倍キャップにし、キャップの1.25倍に増加させます。平均して、操作ごとに[0、1]の割り当てがあります。

例えば、

func BenchmarkMem(b *testing.B) { 
    b.ReportAllocs() 
    var x []int64 
    var a, ac int64 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     c := cap(x) 
     x = append(x, int64(i)) 
     if cap(x) != c { 
      a++ 
      ac += int64(cap(x)) 
     } 
    } 
    b.StopTimer() 
    sizeInt64 := int64(8) 
    B := ac * sizeInt64 // bytes 
    b.Log("op", b.N, "B", B, "alloc", a, "lx", len(x), "cx", cap(x)) 
} 

出力:

op = 50000000については
BenchmarkMem-4  50000000   26.6 ns/op  40 B/op   0 allocs/op 
--- BENCH: BenchmarkMem-4 
    bench_test.go:32: op 1 B 8 alloc 1 lx 1 cx 1 
    bench_test.go:32: op 100 B 2040 alloc 8 lx 100 cx 128 
    bench_test.go:32: op 10000 B 386296 alloc 20 lx 10000 cx 12288 
    bench_test.go:32: op 1000000 B 45188344 alloc 40 lx 1000000 cx 1136640 
    bench_test.go:32: op 50000000 B 2021098744 alloc 57 lx 50000000 cx 50539520 

B/op = floor(2021098744/50000000) = floor(40.421974888) = 40 

allocs/op = floor(57/50000000) = floor(0.00000114) = 0 

読む:

Go Slices: usage and internals

'append' complexity

Arrays, slices (and strings): The mechanics of 'append'は、追記のためにゼロB/OP(ゼロallocs/OP)を有する追加する前に、十分な容量を持つスライスを割り当てます。例えば

var x = make([]int64, 0, b.N)

func BenchmarkZero(b *testing.B) { 
    b.ReportAllocs() 
    var x = make([]int64, 0, b.N) 
    var a, ac int64 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     c := cap(x) 
     x = append(x, int64(i)) 
     if cap(x) != c { 
      a++ 
      ac += int64(cap(x)) 
     } 
    } 
    b.StopTimer() 
    sizeInt64 := int64(8) 
    B := ac * sizeInt64 // bytes 
    b.Log("op", b.N, "B", B, "alloc", a, "lx", len(x), "cx", cap(x)) 
} 

出力を有する:

BenchmarkZero-4  100000000   11.7 ns/op   0 B/op   0 allocs/op 
--- BENCH: BenchmarkZero-4 
    bench_test.go:51: op 1 B 0 alloc 0 lx 1 cx 1 
    bench_test.go:51: op 100 B 0 alloc 0 lx 100 cx 100 
    bench_test.go:51: op 10000 B 0 alloc 0 lx 10000 cx 10000 
    bench_test.go:51: op 1000000 B 0 alloc 0 lx 1000000 cx 1000000 
    bench_test.go:51: op 100000000 B 0 alloc 0 lx 100000000 cx 100000000 

注/ OP周り26.6ナノ秒から/ OP周り11.7ナノ秒にベンチマークCPU時間の短縮。

+0

質問3のアイデアですか? –