要测试的方法
unit.go
package main
func addUpper(n int) int {
res := 0
for i := 1; i <= n-1; i++ {
res += i
}
return res
}
func main() {
}
单元测试文件 必须_test结尾
unit_test.go
//go单元测试
package main
import "testing"
// 编写测试用例 testing 框架会执行_test结尾的文件 并找到Test开头的函数执行
// 执行命令:go test -v 执行全部目录测试
// go test unit_test.go .\unit.go 执行指定文件测试
// go test -v -run TestAddUpper unit_test.go unit.go 执行指定方法
func TestAddUpper(t *testing.T) {
// 调用要测试的函数
res := addUpper(10)
if res != 55 {
t.Fatalf("addUpper(10) 执行错误,期望值=%v 实际值=%v \n", 55, res)
}
// 如果正确 输出日志
t.Logf("addUpper(10) 执行正确。。。")
}
基准测试——获得代码内存占用和运行效率的性能数据
package main
import "testing"
// 基准测试——获得代码内存占用和运行效率的性能数据
// 函数名 Benchmark开头
//go test -v -bench=Add benchmark_test.go
// ns/op”表示每一个操作耗费多少时间(纳秒
// go test -v -bench=Add -benchmem benchmark_test.go
//-bench后添加了 Add,指定只测试 Benchmark_Add() 函数
//-benchmem参数以显示内存分配情况
// 执行正则匹配查询go test -v -bench ^Benchmark_Add$ benchmark_test.go
func Benchmark_Add(b *testing.B) {
var n int
for i := 0; i < b.N; i++ {
n++
}
}
func Benchmark_Add2(b *testing.B) {
var n int
for i := 0; i < b.N; i++ {
n++
}
}
go 编译中间码 可对内存分配进行分析
#查看内存分配 是分配到堆 还是分配到栈 方便查找数据逃逸现象
go tool compile -m .\map.go
#查看变量分配地址
go tool compile -S .\map.go
调试工具对go程序进行调试
#使用linux内置time工具 查看运行时间 调试编译后的可执行文件interface
time ./interface
#测试未编译文件
time go run interface.go
real 0m0.251s //从开始到结束 实际耗时
user 0m0.116s // 用户态耗时
sys 0m0.265s // 内核态耗时
#比内置time更详细的工具 如果没有 需自行安装
/usr/bin/time -v go run interface.go
内存及gc跟踪
gctrace用途主要是用于跟踪GC的不同阶段的耗时与GC前后的内存量对比
#使用的时候仅需在启动的时候添加GODEBUG='gctrace=1'的命令参数即可 linux下可用
#'gctrace=1' 会在汇总每次垃圾回收 回收的内存及耗时 一行是一次垃圾回收汇总信息
GODEBUG='gctrace=1' go run godebug.go
gc 12 @1.512s 6%: 0.016+935+0.072 ms clock, 0.064+0/0.18/934+0.28 ms cpu, 346->346->211 MB, 346 MB goal, 0 MB stacks, 0 MB globals, 4 P
+0.005 ms clock, 0.075+0/0.18/0.12+0.022 ms cpu, 516->516->0 MB, 1033 MB goal, 0 MB stacks, 0 MB globals, 4 P (forced)
依次代表:
12 GC次数编号 依次递增
@1.512s 距离程序开始时的时间
6%: GC占用的时间 百分比
0.016+935+0.072 ms clock GC使用的时间
0.064+0/0.18/934+0.28 ms cpu 垃圾回收占用cup时间
346->346->211 MB GC开始 结束 以及当前活跃堆内存大小 单位为m
346 MB goal 全局堆内存大小
4 P 使用processor的数量
如果每条信息带forced结束 代表程序使用runtime.GC() 调用触发的
通过程序打印内存gc信息
通过runtime库里的ReadMemStats函数查看内存占用
// 通过程序编译后 查看内存 通过runtime库里的ReadMemStats函数查看内存占用
func readMemStats() {
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
log.Printf("===>Alloc:%d(Bytes) HeapIdle: %d(Bytes) HeapReleased: %d(Bytes)", ms.Alloc,
ms.HeapIdle, ms.HeapReleased)
}
go自带的性能分析利器pprof 只需要启动http服务即可通过网页查看
可以查看:
allocs:程序启动之后内存分配的情况
block:导致阻塞操作的一些堆栈跟踪信息
cmdline:当前程序启动的命令行
goroutine:所有当前 goroutine 的堆栈跟踪信息
heap:程序在当前堆上内存分配的情况
mutex:锁资源的竞争的堆栈信息
profile:CPU profile文件。可以在 debug/pprof?seconds=x秒 GET 参数中指定持续时间。点击profile会下载profile文件 获取pprof文件后,使用 go tool pprof x.prof命令分析pprof文件。
例如生成profile文件间隔时间20秒:http://127.0.0.1:6087/debug/pprof/?seconds=20
threadcreate:系统线程的使用情况
trace:当前系统的代码执行的链路情况
import (
"net/http"
_ "net/http/pprof"
)
// 启动pprof
go func() {
log.Println(http.ListenAndServe("127.0.0.1:6087", nil))
}()
cup性能分析
#cup性能分析 点击profile 下载profile文件 使用go 自带pprof进行分析
go tool pprof .\profile
#返回如下数据 会带一个命令行参数 例如输入top
PS D:\golang\go-program> go tool pprof .\profile
Type: cpu
Time: Jul 16, 2023 at 4:34pm (CST)
Duration: 30s, Total samples = 1.75s ( 5.83%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 1.61s, 92.00% of 1.75s total
Showing top 10 nodes out of 66
flat flat% sum% cum cum%
1.31s 74.86% 74.86% 1.31s 74.86% runtime.stdcall3
0.14s 8.00% 82.86% 0.14s 8.00% runtime.stdcall1
0.03s 1.71% 84.57% 0.08s 4.57% runtime.(*pageAlloc).update
0.03s 1.71% 86.29% 0.03s 1.71% runtime.stdcall6
0.02s 1.14% 87.43% 0.04s 2.29% runtime.mergeSummaries
0.02s 1.14% 88.57% 0.02s 1.14% runtime.packPallocSum (inline)
0.02s 1.14% 89.71% 0.02s 1.14% runtime.runqgrab
0.02s 1.14% 90.86% 0.26s 14.86% runtime.schedule
0.01s 0.57% 91.43% 0.01s 0.57% runtime.(*consistentHeapStats).acquire
0.01s 0.57% 92.00% 0.01s 0.57% runtime.(*pageAlloc).chunkOf
(pprof)
注释:
flat :当前函数占用CUP的耗时
flat% :当前函数占用CUP的耗时百分比
sum% :函数占用CPU的耗时累计百分比
cum :当前函数加上调用当前函数的函数占用CPU的总耗时
cum% :当前函数加上调用当前函数的函数占用CPU的总耗时百分比
最后一列: 当前函数名
内存使用分析
#使用pprof工具
go tool pprof http://127.0.0.1:6087/debug/pprof/heap
#返回数据
D:\golang\go-program>go tool pprof http://127.0.0.1:6087/debug/pprof/heap
Fetching profile over HTTP from http://127.0.0.1:6087/debug/pprof/heap
Saved profile in C:\Users\liutiangang\pprof\pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Jul 16, 2023 at 5:26pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 6661.22kB, 100% of 6661.22kB total
Showing top 10 nodes out of 22
flat flat% sum% cum cum%
5125kB 76.94% 76.94% 5125kB 76.94% runtime.allocm
512.20kB 7.69% 84.63% 512.20kB 7.69% runtime.malg
512.02kB 7.69% 92.31% 512.02kB 7.69% runtime.gcBgMarkWorker
512kB 7.69% 100% 512kB 7.69% runtime.doaddtimer
0 0% 100% 512kB 7.69% runtime.bgscavenge
0 0% 100% 3587.50kB 53.86% runtime.mcall
0 0% 100% 512kB 7.69% runtime.modtimer
0 0% 100% 1537.50kB 23.08% runtime.mstart
0 0% 100% 1537.50kB 23.08% runtime.mstart0
0 0% 100% 1537.50kB 23.08% runtime.mstart1
(pprof)
top 命令会列出5个统计数据:
flat: 本函数占用的内存量
flat%: 本函数内存占使用内存总量的百分比
sum%: 前面每一行flat百分比的和
cum: 累计量,main函数调用了函数f,函数f占用的内存量,也会记录进来
cum%: 累计量占总量的百分比
最后一列是当前函数
可视化图形查看及分析
使用上边介绍的pprof 在profile命令行里输入web 即可生成svg格式可视化文件
就可以清晰的查看函数的调用关系 svg图里 方框越大 代表CPU占用越大
D:\golang\go-program>go tool pprof profile
Type: cpu
Time: Jul 16, 2023 at 4:57pm (CST)
Duration: 30.01s, Total samples = 20ms (0.067%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) web
failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in %PATH%
如果报错 提示找不到Graphviz 需要安装工具
安装:
下载地址: https://www.graphviz.org/download/
按照对应系统下载对应安装包即可
golangci-lint
是一个非常流行的 Go 语言代码质量检查工具,发现潜在的错误和性能问题
#安装
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
#检测
golangci-lint run