?????????Щ?????????????????????????????1??????????????????????????????????顣
????д?????????Go?????????????go????????????????????????????????????Go????????????÷???????????????Benchmark??????
????benchmark
????Go??Benchmar???????′??????_test.go???????????????????溯????
????func BenchmarkStringJoin1(b *testing.B) {
????b.ReportAllocs()
????input := []string{"Hello"?? "World"}
????for i := 0; i < b.N; i++ {
????result := strings.Join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????????????????:
????# go test -run=xxx -bench=. -benchtime="3s" -cpuprofile profile_cpu.out
??????????????????????????????benchmark???????????cpu???????????.
??????????????:
????1. -benchtime ???????benchmark?????????
????2. b.ReportAllocs() ????report?а???????????????????????:
BenchmarkStringJoin1-4 300000 4351 ns/op 32 B/op 2 allocs/op
????-4???4??CPU?????У?300000???????????30??Σ?4531ns/op??????????к??4531????32B/op????????з?????32?????棻2 allocs/op????????з?????2?ζ???
????????????????????????????·?????????????????????
?????????????????????????????СС?????:
?? func BenchmarkStringJoin2(b *testing.B) {
????b.ReportAllocs()
????input := []string{"Hello"?? "World"}
????join := func(strs []string?? delim string) string {
????if len(strs) == 2 {
????return strs[0] + delim + strs[1];
????}
????return "";
????};
????for i := 0; i < b.N; i++ {
????result := join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
?????μ?Benchmark??????
????BenchmarkStringJoin2-4 500000 2440 ns/op 16 B/op 1 allocs/op
???????????????????????????????????????60%?????
????cpu profile
??????????benchmark??????????????????????????????????????ú?????????????????????????????????????????????Cpu Profile??????
????Cpu profile??Go??????????????????????????????????memory??block profile??????????????????????????????
????????benchmark?????????????profile_cpu.out?????????????????????????:
??# go tool pprof app.test profile_cpu.out
????Entering interactive mode (type "help" for commands)
????(pprof) top10
????8220ms of 10360ms total (79.34%)
????Dropped 63 nodes (cum <= 51.80ms)
????Showing top 10 nodes out of 54 (cum >= 160ms)
????flat  flat%   sum%        cum   cum%
????2410ms 23.26% 23.26%     4960ms 47.88%  runtime.concatstrings
????2180ms 21.04% 44.31%     2680ms 25.87%  runtime.mallocgc
????1200ms 11.58% 55.89%     1200ms 11.58%  runtime.memmove
????530ms  5.12% 61.00%      530ms  5.12%  runtime.memeqbody
????530ms  5.12% 66.12%     2540ms 24.52%  runtime.rawstringtmp
????470ms  4.54% 70.66%     2420ms 23.36%  strings.Join
????390ms  3.76% 74.42%     2330ms 22.49%  app.BenchmarkStringJoin3B
????180ms  1.74% 76.16%     1970ms 19.02%  runtime.rawstring
????170ms  1.64% 77.80%     5130ms 49.52%  runtime.concatstring3
????160ms  1.54% 79.34%      160ms  1.54%  runtime.eqstring
???????????????????????????????е?????·??????????????????????????????????????svg????pdf???
????# go tool pprof -svg profile_cpu.out > profile_cpu.svg
????# go tool pprof -pdf profile_cpu.out > profile_cpu.pdf
??????????profile_cpu.pdf???:

?????????????????????benchmark????(????????benmark?????????????????)????????????????????????benchmark?????????????
??  go test -run=xxx -bench=BenchmarkStringJoin2B$ -cpuprofile profile_2b.out
????go test -run=xxx -bench=BenchmarkStringJoin2$ -cpuprofile profile_2.out
????go tool pprof -svg profile_2b.out > profile_2b.svg
????go tool pprof -svg profile_2.out > profile_2.svg


??????????????benchmark????????(??????????)runtime.concatstrings???????????????????????????????????????????????????????????????????flame graphs ???
????“A flame graph is a good way to drill down your benchmarks?? finding your bottlenecks #golang” via @TitPetric

?????????????????????????Щ???ο?á?

??????????Щ?????????? uber/go-torch???????????????https://github.com/brendangregg/FlameGraph???????????????????????????????frame graph?????????????????????????????
????#!/bin/bash
????# install flamegraph scripts
????if [ ! -d "/opt/flamegraph" ]; then
????echo "Installing flamegraph (git clone)"
????git clone --depth=1 https://github.com/brendangregg/FlameGraph.git /opt/flamegraph
????fi
????# install go-torch using docker
????if [ ! -f "bin/go-torch" ]; then
????echo "Installing go-torch via docker"
????docker run --net=party --rm=true -it -v $(pwd)/bin:/go/bin golang go get github.com/uber/go-torch
????# or if you have go installed locally: go get github.com/uber/go-torch
????fi
????PATH="$PATH:/opt/flamegraph"
????bin/go-torch -b profile_cpu.out -f profile_cpu.torch.svg
??????????????benchmark?·?????????????????????cpu profile????????????benchmark?У????????????debug????????????????????????????????????к?????????????? ???????????????benchmark????
   package main
????import "testing"
????import "strings"
????func BenchmarkStringJoin1(b *testing.B) {
????b.ReportAllocs()
????input := []string{"Hello"?? "World"}
????for i := 0; i < b.N; i++ {
????result := strings.Join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????func BenchmarkStringJoin1B(b *testing.B) {
????b.ReportAllocs()
????for i := 0; i < b.N; i++ {
????input := []string{"Hello"?? "World"}
????result := strings.Join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????func BenchmarkStringJoin2(b *testing.B) {
????b.ReportAllocs()
????input := []string{"Hello"?? "World"}
????join := func(strs []string?? delim string) string {
????if len(strs) == 2 {
????return strs[0] + delim + strs[1];
????}
????return "";
????};
????for i := 0; i < b.N; i++ {
????result := join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????func BenchmarkStringJoin2B(b *testing.B) {
????b.ReportAllocs()
????join := func(strs []string?? delim string) string {
????if len(strs) == 2 {
????return strs[0] + delim + strs[1];
????}
????return "";
????};
????for i := 0; i < b.N; i++ {
????input := []string{"Hello"?? "World"}
????result := join(input?? " ")
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????func BenchmarkStringJoin3(b *testing.B) {
????b.ReportAllocs()
????input := []string{"Hello"?? "World"}
????for i := 0; i < b.N; i++ {
????result := input[0] + " " + input[1];
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}
????func BenchmarkStringJoin3B(b *testing.B) {
????b.ReportAllocs()
????for i := 0; i < b.N; i++ {
????input := []string{"Hello"?? "World"}
????result := input[0] + " " + input[1];
????if result != "Hello World" {
????b.Error("Unexpected result: " + result)
????}
????}
????}