go内存分析(基准测试和profile生成)

866 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

在前一篇文章中,go逃逸分析通过使用一个在goroutine的堆栈上共享一个值的例子讲解逃逸分析的基础知识。为了更清晰的讲解逃逸分析的情况,这篇文章调试一个简单的程序,查看编译器如何分配值。

情景

给定一个字节流,编写一个函数来查找字符串elvis并将其替换为字符串Elvis

这篇文章将重点关注algOne函数,使用io包编写algOne函数。 可以使用algTwo函数测试内存和cpu概要(cpu profile)文件。使用的输入数据和algOne函数将要产生的预期输出如下。

输入: abcelvisaElvisabcelviseelvisaelvisaabeeeelvise l v i saa bb e l v i saa elvi selvielviselvielvielviselvi1elvielviselvis

输出: abcElvisaElvisabcElviseElvisaElvisaabeeeElvise l v i saa bb e l v i saa elvi selviElviselvielviElviselvi1elviElvisElvis

func algOne(data []byte, find []byte, repl []byte, output *bytes.Buffer) {
	input := bytes.NewBuffer(data)
	size := len(find)
	buf := make([]byte, size)
	end := size - 1
	if n, err := io.ReadFull(input, buf[:end]); err != nil {
		output.Write(buf[:n])
		return
	}
	for {
		if _, err := io.ReadFull(input, buf[:end]); err != nil {
			output.Write(buf[:end])
			return
		}
		if bytes.Compare(buf, find) == 0 {
			output.Write(repl)
			if n, err := io.ReadFull(input, buf[:end]); err != nil {
				output.Write(buf[:n])
				return
			}
			continue
		}
		output.WriteByte(buf[0])
		copy(buf, buf[1:])
	}
}
  • data:数据流
  • find:需要替换的字符串
  • repl:替换的字符串
  • io.ReadFull:该函数从第一个参数input中读取第二个参数buf长度的数据,并写入buf中

基准测试(Benchmark)

想知道的是这个函数的性能如何,以及它对堆的压力有多大。 为了了解这一点,我们将运行一个基准测试。有了这个基准测试函数,我们就可以使用-bench、-benchtime和-benchmem开关对它进行测试。在运行基准测试之后,我们可以看到algOne函数正在为每个操作分配两个值,为117字节。

func BenchmarkAlgorighmOne(b *testing.B) {
	var output bytes.Buffer
	in := []byte("abcelvisaElvisabcelviseelvisaelvisaabeeeelvise l v i saa bb e l v i saa elviselvielviselvielvielviselvi1elvielviselvis")
	find := []byte("elvis")
	repl := []byte("Elvis")
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		output.Reset()
		algOne(in, find, repl, &output)
	}
}
go test -run none -bench AlgorithmOne -benchtime 3s -benchmem
BenchmarkAlgorithmOne-8    	2000000 	     2522 ns/op       117 B/op  	      2 allocs/op

分析数据生成(Profile)

我们需要知道函数中的哪些代码行导致了这些分配。 要了解这一点,我们需要为这个基准生成分析数据。

go test -run none -bench AlgorithmOne -benchtime 3s -benchmem -memprofile mem.out
BenchmarkAlgorithmOne-8    	2000000 	     2570 ns/op       117 B/op  	      2 allocs/op

一旦基准测试完成,测试工具就会生成两个新文件。源代码在一个名为memcpu的文件夹中, 生成的两个新文件为mem.out,mem.cpu.test。 输出文件包含profile文件和memcpu.test测试文件,profile文件和测试二进制文件就绪后,可以采用go工具进行性能分析。下一篇文章讲解如何使用go的pprof工具进行性能分析。

总结

使用io包构建了字符串查找,替换函数,并为其编写了基准测试,生成profile数据。本文参考并翻译了参考文献第一篇。

参考

www.ardanlabs.com/blog/2017/0…