【问题标题】:Output from benchmem基准测试的输出
【发布时间】:2019-10-08 20:19:44
【问题描述】:

我在使用内存分析器运行基准测试时看到以下输出

SomeFunc             100      17768876 ns/op         111 B/op          0 allocs/op

我不明白输出 - 0 allocs/op 但分配了 111 B?知道这意味着什么吗?我的函数是否在堆上分配内存?

【问题讨论】:

  • 请注意,这些是四舍五入的值:如果您的基准分配例如在您的情况下,只有每第二次迭代(例如总共 50 个分配)分配/操作将是 50/100 = 0。(顺便说一句:在 18 毫秒/操作算法上无需担心 100 字节/操作。)
  • @Volker 这就是我想补充的,也许这个问题值得重新讨论。

标签: go performance-testing


【解决方案1】:

基准测试结果收集在testing.BenchmarkResult 类型的值中:

type BenchmarkResult struct {
        N         int           // The number of iterations.
        T         time.Duration // The total time taken.
        Bytes     int64         // Bytes processed in one iteration.
        MemAllocs uint64        // The total number of memory allocations; added in Go 1.1
        MemBytes  uint64        // The total number of bytes allocated; added in Go 1.1
}

BencharkResult.AllocedBytesPerOp()BenchmarkResult.AllocsPerOp() 返回每​​个操作分配的内存和分配的值。他们记录了返回值是:

AllocedBytesPerOp 返回 r.MemBytes / r.N

AllocsPerOp 返回 r.MemAllocs / r.N

所以结果是整数除法。这意味着如果一个基准函数在不同的调用中执行不同数量的分配,结果可能不是整数,但小数部分被丢弃(这就是整数除法的工作原理)。

因此,如果一个函数平均执行少于 1 次分配,您将看到 0 allocs/op,但如果其平均每次调用至少 1 个字节,则分配的内存可能大于 0。

我们来看一个例子:

var (
    counter   int
    falseCond bool // Always false at runtime
)

func AvgHalfAllocs() {
    counter++
    if counter%2 == 0 {
        return
    }
    buf := make([]byte, 128)
    if falseCond {
        fmt.Println(buf)
    }
}

func AvgOneAndHalfAllocs() {
    for i := 0; i < 3; i++ {
        AvgHalfAllocs()
    }
}

这里AvgHalfAllocs() 平均每次调用分配一半,它通过从一半调用返回而不分配任何东西来做到这一点,并在另一半调用中只进行 1 次分配。

AvgOneAndHalfAllocs() 平均每次调用执行 1.5 次分配,因为它调用了 AvgHalfAllocs() 3 次。

falseCond 变量和fmt.Println() 调用的目的只是为了让编译器不会优化我们的分配,但永远不会调用fmt.Println(),因此它不会干扰分配.

像这样对上述 2 个函数进行基准测试:

func BenchmarkAvgHalfAllocs(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AvgHalfAllocs()
    }
}

func BenchmarkAvgOneAndHalfAllocs(b *testing.B) {
    for i := 0; i < b.N; i++ {
        AvgOneAndHalfAllocs()
    }
}

结果是:

BenchmarkAvgHalfAllocs-4          50000000    29.2 ns/op    64 B/op   0 allocs/op
BenchmarkAvgOneAndHalfAllocs-4    20000000    92.0 ns/op   192 B/op   1 allocs/op

如您所见,在 AvgHalfAllocs() 的情况下,每次调用的 0.5 个分配被截断为 0,在 AvgOneAndHalfAllocs() 的情况下,1.5 被截断为 1。

AvgHalfAllocs() 的平均分配内存为 0.5 * 128 字节 = 64 字节。

AvgOneAndHalfAllocs() 的平均分配内存为 1.5 * 128 字节 = 192 字节。

【讨论】:

  • 谢谢@icza。这是一个很好的答案
猜你喜欢
  • 1970-01-01
  • 2013-04-19
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多