package main
import ("fmt""runtime")
func main(){
buf := make([]byte,1024)
n := runtime.Stack(buf,true)
fmt.Printf("%s\n", buf[:n])}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
$ go run main.go
# 输出如下 (你的输出代码路径应该和这里的不一样)
goroutine 1[running]:
main.main()/home/codes/go-high-performance/main.go:10+0x45
...
1.
2.
3.
4.
5.
6.
7.
测试代码如下
package performance
import ("runtime""testing")
func Benchmark_StackDump(b *testing.B){
for i :=0; i < b.N; i++{
buf := make([]byte,1024)
n := runtime.Stack(buf,true)
_ = buf[:n]}}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
运行测试,并将基准测试结果写入文件:
# 运行 1000 次,统计内存分配
$ go test -run='^$'-bench=. -count=1-benchtime=1000x -benchmem > slow.txt
1.
2.
runtime.Caller
通过标准库提供的 runtime.Caller 相关 API 来获取。
示例
package main
import ("fmt""runtime")
func main(){
for i :=0;; i++{
if _, file, line, ok := runtime.Caller(i); ok {
fmt.Printf("file: %s, line: %d\n", file, line)} else {
break
}}}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
$ go run main.go
# 输出如下 (你的输出代码路径应该和这里的不一样)
file:/home/codes/go-high-performance/main.go, line:10
file:/usr/local/go/src/runtime/proc.go, line:250
file:/usr/local/go/src/runtime/asm_amd64.s, line:1594
...
package main
import ("fmt""runtime""strconv""strings")
func main(){
pcs := make([]uintptr,16)
n := runtime.Callers(0, pcs)
frames := runtime.CallersFrames(pcs[:n])
var sb strings.Builder
for {
frame, more := frames.Next()
sb.WriteString(frame.Function)
sb.WriteByte('\n')
sb.WriteByte('\t')
sb.WriteString(frame.File)
sb.WriteByte(':')
sb.WriteString(strconv.Itoa(frame.Line))
sb.WriteByte('\n')
if !more {
break
}}
fmt.Println(sb.String())}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
$ go run main.go
# 输出如下 (你的输出代码路径应该和这里的不一样)
runtime.Callers/usr/local/go/src/runtime/extern.go:247
main.main/home/codes/go-high-performance/main.go:12
runtime.main/usr/local/go/src/runtime/proc.go:250
runtime.goexit/usr/local/go/src/runtime/asm_amd64.s:1594
...
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
测试代码
package performance
import ("runtime""strconv""strings""testing")
func stackDump() string {
pcs := make([]uintptr,16)
n := runtime.Callers(0, pcs)
frames := runtime.CallersFrames(pcs[:n])
var buffer strings.Builder
for {
frame, more := frames.Next()
buffer.WriteString(frame.Function)
buffer.WriteByte('\n')
buffer.WriteByte('\t')
buffer.WriteString(frame.File)
buffer.WriteByte(':')
buffer.WriteString(strconv.Itoa(frame.Line))
buffer.WriteByte('\n')
if !more {
break
}}
return buffer.String()}
func Benchmark_StackDump(b *testing.B){
for i :=0; i < b.N; i++{
_ = stackDump()}}
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
运行测试,并将基准测试结果写入文件:
# 运行 1000 次,统计内存分配
$ go test -run='^$'-bench=. -count=1-benchtime=1000x -benchmem > fast.txt
1.
2.
使用 benchstat 比较差异
$ benchstat -alpha=100 fast.txt slow.txt
# 输出如下
name old time/op new time/op delta
_StackDump-82.28µs ± 0%68.89µs ± 0%+2926.85%(p=1.000 n=1+1)
name old alloc/op new alloc/op delta
_StackDump-81.36kB ± 0%1.02kB ± 0%-24.71%(p=1.000 n=1+1)
name old allocs/op new allocs/op delta
_StackDump-812.0 ± 0%1.0 ± 0%-91.67%(p=1.000 n=1+1)