douyingtai6662 2017-02-11 04:49
浏览 110
已采纳

进行基准测试和gc:B / op分配/ op

benchmark code:

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

result:

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

question/s:

  • where did 40 B/op come from? (any way of tracing + instructions is greatly appreciated)
  • how is it possible to have 40 B/op while having 0 allocs?
  • which one affects GC and how? (B/op or allocs/op)
  • is it really possible to have 0 B/op using append?
  • 写回答

1条回答 默认 最新

  • dqg2269 2017-02-11 13:49
    关注

    The Go Programming Language Specification

    Appending to and copying slices

    The variadic function append appends zero or more values x to s of type S, which must be a slice type, and returns the resulting slice, also of type S.

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

    If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.

    For your example, on average, [40, 41) bytes per operation are allocated to increase the capacity of the slice when necessary. The capacity is increased using an amortized constant time algorithm: up to len 1024 increase to 2 times cap then increase to 1.25 times cap. On average, there are [0, 1) allocations per operation.

    For example,

    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))
    }
    

    Output:

    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
    

    For op = 50000000,

    B/op = floor(2021098744 / 50000000) = floor(40.421974888) = 40
    
    allocs/op = floor(57 / 50000000) = floor(0.00000114) = 0
    

    Read:

    Go Slices: usage and internals

    Arrays, slices (and strings): The mechanics of 'append'

    'append' complexity

    To have zero B/op (and zero allocs/op) for append, allocate a slice with sufficient capacity before appending.

    For example, with 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))
    }
    

    Output:

    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
    

    Note the reduction in benchmark CPU time from around 26.6 ns/op to around 11.7 ns/op.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图