例子
源码文件
//fib.go
package main
//
func FibRaw(x int) int {
if x == 0 {
return 0
} else if x <= 2 {
return 1
} else {
return FibRaw(x-2) + FibRaw(x-1)
}
}
//
var cache = make(map[int]int)
func FibCache(x int) int {
if val, found := cache[x]; found {
return val
}
var ret int
if x == 0 {
ret = 0
} else if x <= 2 {
ret = 1
} else {
ret = FibCache(x-2) + FibCache(x-1)
}
cache[x] = ret
return ret
}
测试文件
//fib_test.go
package main
//bench
func BenchmarkFibRaw(b *testing.B) {
for i := 0; i < b.N; i++ {
FibRaw(i % 40)
}
}
func BenchmarkFibCache(b *testing.B) {
for i := 0; i < b.N; i++ {
FibCache(i % 40)
}
}
//prof
func fibCacheLoop(times int) {
for i := 0; i < times; i++ {
FibCache(40)
}
}
func BenchmarkFibPro(b *testing.B) {
FibRaw(40)
fibCacheLoop(30000000)
}
性能测试
运行全部测试用例,用 . 模式匹配所有性能测试用例
sfw@ux ~/src/fib/output $ go test -run=xxx -bench=. ../.
goos: linux
goarch: amd64
BenchmarkFibRaw-2 100 99909281 ns/op
BenchmarkFibCache-2 20000000 116 ns/op
BenchmarkFibPro-2 1 6975007074 ns/op
PASS
ok _/home/sfw/src/fib 19.446s
运行某一类测试用例,比如 FibCache
sfw@ux ~/src/fib/output $ go test -run=xxx -bench=FibCache ../.
goos: linux
goarch: amd64
BenchmarkFibCache-2 20000000 116 ns/op
PASS
ok _/home/sfw/src/fib 2.457s
性能剖析
涉及的工具
- pprof ( go 自带 )
- graphviz ( 第三方 )
- go-torch ( 第三方 )
cpu 性能剖析
-cpurofile 参数生成性能文件
sfw@ux ~/src/fib/output $ go test -run=xxx -bench=FibPro ../. -cpuprofile=cpu.prof
goos: linux
goarch: amd64
BenchmarkFibPro-2 1 6215340183 ns/op
PASS
ok _/home/sfw/src/fib 6.428s
-rwxrwxrwx 1 root root 5.1K 5月 29 16:44 cpu.prof*
1, -run=xxx 这里 “xxx” 模式匹配不到任何功能测试函数,所以不执行功能测试.还可写成 -run=NONE, -run=“none” 等匹配不到但又能自解释的模式.
2, Test 和 Benchmark 测试用例中不用加入 runtime.pprof 包中的性能测函数,已经默认打开了.只需指定输出文件即可 -cpuprofile=cpu.prof. 这对要对某个函数进行性能剖析非常方便.
3, Test 函数一般不导出性能剖析文件,因为他们的用途是验证功能的正确与否. Bench 函数是专门用来剖析性能的,正适合导出性能剖析文件,进行性能刨析.
pprof 工具解析性能文件
sfw@ux ~/src/fib/output $ go tool pprof fib.test cpu.prof
File: fib.test
Type: cpu
Time: May 29, 2019 at 5:23pm (CST)
Duration: 8.76s, Total samples = 8.50s (97.00%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top // <--- top 指令
Showing nodes accounting for 8440ms, 99.29% of 8500ms total
Dropped 14 nodes (cum <= 42.50ms)
flat flat% sum% cum cum%
3530ms 41.53% 41.53% 3530ms 41.53% _/home/sfw/src/fib.FibRaw
3320ms 39.06% 80.59% 4020ms 47.29% runtime.mapaccess2_fast64
570ms 6.71% 87.29% 570ms 6.71% runtime.aeshash64
520ms 6.12% 93.41% 4540ms 53.41% _/home/sfw/src/fib.FibCache
410ms 4.82% 98.24% 4950ms 58.24% _/home/sfw/src/fib.fibCacheLoop
90ms 1.06% 99.29% 90ms 1.06% runtime.add
0 0% 99.29% 8480ms 99.76% _/home/sfw/src/fib.BenchmarkFibPro
0 0% 99.29% 8480ms 99.76% testing.(*B).run1.func1
0 0% 99.29% 8480ms 99.76% testing.(*B).runN
(pprof) list FibCache // <--- list 指令
Total: 8.50s
ROUTINE ======================== _/home/sfw/src/fib.FibCache in /home/sfw/src/fib/fib.go
520ms 4.54s (flat, cum) 53.41% of Total
. . 12:}
. . 13:
. . 14://
. . 15:var cache = make(map[int]int)
. . 16:
150ms 150ms 17:func FibCache(x int) int {
240ms 4.26s 18: if val, found := cache[x]; found {
130ms 130ms 19: return val
. . 20: }
. . 21:
. . 22: var ret int
. . 23: if x == 0 {
. . 24: ret = 0
graphviz 的 svg 指令生成 svg 文件
(pprof) svg // <--- svg 指令
Generating report in profile001.svg
1,从图中可以看出 FibRaw 和 fibCacheLoop 的耗时比是 2:3, fibCacheLoop 调用了 30000000 次 FibCache, 所以 FibRaw 的 cpu 耗时是 FibCache 的 20000000 倍(忽略函数调,用缓存等).
2,如果要对比的两个函数性能相差太多时,不作放大处理(如 FibCache),值小的那个可能会显示0,就是被忽略了,那样就没法量化比较了,需要放大小的一方.
go-torch 生成 svg 图
sfw@ux ~/src/fib/output $ go-torch cpu.prof ../.
INFO[17:38:48] Run pprof command: go tool pprof -raw -seconds 30 cpu.prof ../.
INFO[17:38:48] Writing svg to torch.svg