当前位置: 代码网 > it编程>前端脚本>Golang > Go语言如何实现Benchmark函数

Go语言如何实现Benchmark函数

2025年02月14日 Golang 我要评论
背景go 必须要 test 才能跑benchmark,导致一些情况下想要在main函数中测试benchmark会麻烦一些,因此我实现了一个简单的且没有开销的benchmark函数,方便使用!其次也方便

背景

go 必须要 test 才能跑benchmark,导致一些情况下想要在main函数中测试benchmark会麻烦一些,因此我实现了一个简单的且没有开销的benchmark函数,方便使用!其次也方便大家学习下如何实现一个零开销的benchmark框架!

benchamrk 实现

对于有timeout的benchamrk,每次都去比较 time.before(timeout) 开销非常的大,而且 benchmark 的对外函数也不能是一个空函数一定要带 count ,因为函数调用大概会劣化 ns 级别!

所以一般的benchmark算法都是梯度benchmark,即 1,10,100,1000,10000,100000,1000000 ... 的数量级去benchmark,好处就是避免了大量的time.since 计算开销,因为time.since单次在 30ns 左右(linux环境下),开销非常大的!

package pprof

import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)

func parallelbenchmark(name string, thread int, duration time.duration, execute func(count int)) {
    wg := sync.waitgroup{}
    wg.add(thread)
    totalcount := uint64(0)
    totalspend := uint64(0)
    for i := 0; i < thread; i++ {
       go func() {
          defer wg.done()
          spend, count := benchmark(duration, execute)
          atomic.adduint64(&totalspend, uint64(spend))
          atomic.adduint64(&totalcount, uint64(count))
       }()
    }
    wg.wait()
    fmt.printf("name=%s thread=%d duration=%s total=%d avg=%s\n", name, thread, duration, totalcount, avg(time.duration(totalspend), int(totalcount)))
}

func avg(spend time.duration, count int) string {
    avg := float64(spend) / float64(count)
    if avg > 100 {
       return time.duration(avg).string()
    }
    return fmt.sprintf("%.4fns", avg)
}

func benchmark(duration time.duration, bench func(count int)) (time.duration, int) {
    const maxtotalcount = 1000000000 // 10e
    count := 1
    totalspend := time.duration(0)
    totalcount := 0
    for {
       start := time.now()
       bench(count)
       spend := time.since(start)

       totalspend = totalspend + spend
       totalcount = totalcount + count

       if totalcount >= maxtotalcount {
          break
       }
       subspend := duration - totalspend
       if subspend <= 0 {
          break
       }
       count = totalcount*10 - totalcount
       if subcount := int(float64(subspend) / (float64(totalspend) / float64(totalcount))); count > subcount {
          count = subcount
       }
    }
    return totalspend, totalcount
}

profile 实现

package pprof

import (
    "net/http"
    _ "net/http/pprof"
    "os"
    "runtime"
    "runtime/pprof"
)

// initpprof
// go initpprof()
func initpprof() {
    err := http.listenandserve(":12345", http.defaultservemux)
    if err != nil {
       panic(err)
    }
}

func startcpuprofile(filename string) (stop func()) {
    f, err := os.create(filename)
    if err != nil {
       panic(err)
    }
    if err := pprof.startcpuprofile(f); err != nil {
       if err := f.close(); err != nil {
          panic(err)
       }
       panic(err)
    }
    return func() {
       pprof.stopcpuprofile()
       if err := f.close(); err != nil {
          panic(err)
       }
    }
}

func startmemprofile(filename string) (stop func()) {
    f, err := os.create(filename)
    if err != nil {
       panic(err)
    }
    return func() {
       defer func() {
          if err := f.close(); err != nil {
             panic(err)
          }
       }()
       runtime.gc() // get up-to-date statistics
       if err := pprof.writeheapprofile(f); err != nil {
          panic(err)
       }
    }
}

例子

package main

import (
	"github.com/anthony-dong/golang/pkg/pprof"
	"sync"
	"time"
)

func main() {
	// 记录 cup pprof
	//stop := pprof.startcpuprofile("cpu.out")
	//defer stop()

	// 并发测试 sync map的性能
	mm := sync.map{}
	pprof.parallelbenchmark("test1", 64, time.second, func(count int) {
		for i := 0; i < count; i++ {
			mm.store(i%10000, 1)
		}
	})
	// name=test1 thread=32 duration=1s total=6708009 avg=4.772µs
	// name=test1 thread=64 duration=1s total=6883456 avg=9.3µs
}

到此这篇关于go语言如何实现benchmark函数的文章就介绍到这了,更多相关go benchmark内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com