32

如果你只知道 go test 用于单元测试就太 LOW 了

 4 years ago
source link: https://mp.weixin.qq.com/s/LDYJMZ72k9PCSiBwJAMKlQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

如果你只知道 go test 用于单元测试就太 LOW 了

原创 站长polaris Go语言中文网 4天前

点击上方蓝色“Go语言中文网”关注我们,领全套Go资料,每天学习 Go 语言

640?wx_fmt=png

“A Journey With Go” 专属插图,由 Renee French 根据原始 Go Gopher 制作。

ℹ️ 本文基于 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 对程序进行了什么样的修改:

640?wx_fmt=png

变量 GoCover_0_313837343662366134383538 是一个标志数组,其中每个键是一个代码块,当代码实际进入这一块时对应的标志设置为 1.

你可以在我的文章 “Go: Compiler Phases”[4] 中找到更多关于 SSA 的信息。

生成的代码将稍后在管理代码覆盖率报告的函数中使用。我们可以通过使用 objdump 命令反汇编代码覆盖期间生成的目标文件来进行验证。运行 go test -cover -o main.o && Go tool objdump main.go 将反汇编代码并显示缺少的部分。它首先初始化并在自动生成的 init 函数中注册 coverage:

640?wx_fmt=png

test.go 添加的 init 方法

然后,如前所述,测试将在执行期间收集覆盖率数据并且会触发一个方法来实际写入和显示覆盖率:

640?wx_fmt=png

go test 调用的 after 函数

CPU 分析

跟踪 CPU 使用率的策略则有所不同。Go 会停止程序并收集正在运行程序的样本。这里是未开启 CPU 分析的代码的 trace:

640?wx_fmt=png

这里是相同代码开启了 CPU 分析的 trace:

640?wx_fmt=png

增加的 trace 与 pprof 及性能分析相关。这里是其中一个的放大图:

640?wx_fmt=png

profileWriter 方法将循环调用,每 100 毫秒收集 CPU 数据,以在性能分析结束时最终生成报告。

内存分析包含在源码中,并已集成在内存分配系统中。在使用 -memprofile 开启内存分析[5]的情况下,位于 malloc.go[6] 中的内存分配器,将对已分配的内存进行分析[7]。这里,依然可以通过反汇编代码进行验证。这里是内存分配器的使用:

640?wx_fmt=png

开启了内存分配分析

你可以在我的文章 “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] 荣誉推出

[1]

代码覆盖率: 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/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK