go test 的这些用途你都懂吗?
共 3427字,需浏览 7分钟
·
2021-07-28 08:07
点击上方“Go编程时光”,选择“加为星标”
第一时间关注Go技术干货!
本文是 Go语言中文网组织的 GCTT 翻译,发布在 Go语言中文网公众号,转载请前往联系授权。另本文基于 Go 1.13 。
go test
命令提供了许多出色的功能,比如代码覆盖率,CPU 和 内存分析。要提供这些统计信息,Go 就需要一种方式来跟踪 CPU 使用率,或在代码覆盖中跟踪一个函数何时被用到。
性能测量
Go 使用多种方式来产生这些统计信息:
动态插入性能测量语句,使其可以跟踪到代码何时进入一个函数或条件。这个策略在代码覆盖率[1]中使用。 每秒记录多次程序样本。这个策略在CPU 分析[2]中用到。 在代码中使用静态 hook,以便在执行期间调用所需函数。这个策略在内存分析中用到。
我们来写一个简单的程序并回顾所有内容。这是我们在后面的章节将使用的代码:
package main
import "math/rand"
func main() {
println(run())
}
//go:noinline
func run() int {
a := 0
for i:= 0; i < rand.Intn(100000); i++ {
if i % 2 == 0 {
add(&a)
} else {
sub(&a)
}
}
return a
}
//go:noinline
func add(a *int) {
*a += rand.Intn(10)
}
//go:noinline
func sub(a *int) {
*a -= rand.Intn(10)
}
main.go 托管在 [GitHub] (https://github.com/) 查看[3]
代码覆盖率
通过 GOSSAFUNC=run Go test -cover
命令生成的 SSA 代码,我们可以查看 Go 对程序进行了什么样的修改:
变量 GoCover_0_313837343662366134383538
是一个标志数组,其中每个键是一个代码块,当代码实际进入这一块时对应的标志设置为 1.
你可以在我的文章 “Go: Compiler Phases”[4] 中找到更多关于 SSA 的信息。
生成的代码将稍后在管理代码覆盖率报告的函数中使用。我们可以通过使用 objdump
命令反汇编代码覆盖期间生成的目标文件来进行验证。运行 go test -cover -o main.o && Go tool objdump main.go
将反汇编代码并显示缺少的部分。它首先初始化并在自动生成的 init 函数中注册 coverage:
然后,如前所述,测试将在执行期间收集覆盖率数据并且会触发一个方法来实际写入和显示覆盖率:
CPU 分析
跟踪 CPU 使用率的策略则有所不同。Go 会停止程序并收集正在运行程序的样本。这里是未开启 CPU 分析的代码的 trace:
这里是相同代码开启了 CPU 分析的 trace:
增加的 trace 与 pprof
及性能分析相关。这里是其中一个的放大图:
profileWriter
方法将循环调用,每 100 毫秒收集 CPU 数据,以在性能分析结束时最终生成报告。
内存分析
内存分析包含在源码中,并已集成在内存分配系统中。在使用 -memprofile
开启内存分析[5]的情况下,位于 malloc.go[6] 中的内存分配器,将对已分配的内存进行分析[7]。这里,依然可以通过反汇编代码进行验证。这里是内存分配器的使用:
开启了内存分配分析
你可以在我的文章 “Go: Unknown Parts of the Test Package[8]” 中找到更多关于 test 包的信息.
via: https://medium.com/a-journey-with-go/go-instrumentation-in-go-e845cdae0c51
作者:Vincent Blanchon[9]译者:krystollia[10]校对:polaris1119[11]
本文由 GCTT[12] 原创编译,Go 中文网[13] 荣誉推出,发布在 Go语言中文网公众号,转载请联系我们授权。
参考资料
代码覆盖率: https://golang.org/doc/go1.2#cover
[2]CPU 分析: https://blog.golang.org/profiling-go-programs
[3]GitHub] (https://github.com/) [查看: https://gist.github.com/blanchonvincent/d4ed01d31b3ed99eb5cd87629ecfe926/raw/1fbac76f932d020a2b172b2385fb1cda69b83b1e/main.go
[4]“Go: Compiler Phases”: https://medium.com/@blanchon.vincent/go-compiler-phases-4e5a153ca889
[5]开启内存分析: https://github.com/golang/go/blob/release-branch.go1.13/src/cmd/compile/internal/gc/util.go#L55-L77
[6]malloc.go: https://github.com/golang/go/blob/release-branch.go1.13/src/runtime/malloc.go#L877
[7]对已分配的内存进行分析: https://github.com/golang/go/blob/release-branch.go1.13/src/runtime/malloc.go#L1097-L1105
[8]Go: Unknown Parts of the Test Package: https://medium.com/a-journey-with-go/go-unknown-parts-of-the-test-package-df8988b2ef7f
[9]Vincent Blanchon: https://medium.com/@blanchon.vincent
[10]krystollia: https://github.com/krystollia
[11]polaris1119: https://github.com/polaris1119
[12]GCTT: https://github.com/studygolang/GCTT
[13]Go 中文网: https://studygolang.com/
⬇⬇⬇