Go語(yǔ)言使用benchmark進(jìn)行性能測(cè)試

在日常開(kāi)發(fā)中,基準(zhǔn)測(cè)試是必不可少的逆趣,基準(zhǔn)測(cè)試主要是通過(guò)測(cè)試CPU和內(nèi)存的效率問(wèn)題苹支,來(lái)評(píng)估被測(cè)試代碼的性能,進(jìn)而找到更好的解決方案俱济。

而Go語(yǔ)言中自帶的benchmark則是一件非常神奇的測(cè)試?yán)魉皇恰S辛怂_(kāi)發(fā)者可以方便快捷地在測(cè)試一個(gè)函數(shù)方法在串行或并行環(huán)境下的基準(zhǔn)表現(xiàn)蛛碌。指定一個(gè)時(shí)間(默認(rèn)是1秒)聂喇,看測(cè)試對(duì)象在達(dá)到或超過(guò)時(shí)間上限時(shí),最多能被執(zhí)行多少次和在此期間測(cè)試對(duì)象內(nèi)存分配情況。

1 benchmark的常見(jiàn)用法

1.1 如何寫一個(gè)benchmark的基準(zhǔn)測(cè)試

import (
    "fmt"
    "testing"
)
func BenchmarkSprint(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        fmt.Sprint(i)
    }
}

對(duì)以上代碼做如下說(shuō)明:

  1. 基準(zhǔn)測(cè)試代碼文件必須是_test.go結(jié)尾希太,和單元測(cè)試一樣克饶;
  2. 基準(zhǔn)測(cè)試的函數(shù)以Benchmark開(kāi)頭;
  3. 參數(shù)須為 *testing.B誊辉;
  4. 基準(zhǔn)測(cè)試函數(shù)不能有返回值矾湃;
  5. b.ResetTimer是重置計(jì)時(shí)器,這樣可以避免for循環(huán)之前的初始化代碼的干擾堕澄;
  6. b.N是基準(zhǔn)測(cè)試框架提供的邀跃,Go會(huì)根據(jù)系統(tǒng)情況生成,不用用戶設(shè)定蛙紫,表示循環(huán)的次數(shù)拍屑,因?yàn)樾枰磸?fù)調(diào)用測(cè)試的代碼,才可以評(píng)估性能坑傅;

運(yùn)行:go test -bench=. -run=none 命令得到以下結(jié)果

image-20210715210837018

運(yùn)行benchmark基準(zhǔn)測(cè)試也要用到 go test 命令僵驰,不過(guò)我們后面需要加上-bench=參數(shù),接受一個(gè)表達(dá)式作為參數(shù)唁毒,匹配基準(zhǔn)測(cè)試的函數(shù)蒜茴,"."一個(gè)點(diǎn)表示運(yùn)行所有的基準(zhǔn)測(cè)試。

因?yàn)槟J(rèn)情況下 go test 會(huì)運(yùn)行單元測(cè)試浆西,為了防止單元測(cè)試的輸出影響我們查看基準(zhǔn)測(cè)試的結(jié)果矮男,可以使用-run=匹配一個(gè)從來(lái)沒(méi)有的單元測(cè)試方法,過(guò)濾掉單元測(cè)試的輸出室谚,我們這里使用none,因?yàn)槲覀兓旧喜粫?huì)創(chuàng)建這個(gè)名字的單元測(cè)試方法崔泵。

接下來(lái)再解釋下輸出的結(jié)果:

  • 函數(shù)名后面的-8秒赤,表示運(yùn)行時(shí)對(duì)應(yīng)的 GOMAXPROCS 的值;
  • 接著的 1230048 表示運(yùn)行 for 循環(huán)的次數(shù)憎瘸,也就是調(diào)用被測(cè)試代碼的次數(shù)入篮,也就是在b.N的范圍內(nèi)執(zhí)行的次數(shù);
  • 最后的 112.9 ns/op表示每次需要花費(fèi) 112.9 納秒幌甘;

以上是測(cè)試時(shí)間默認(rèn)是1秒潮售,也就是1秒的時(shí)間,調(diào)用 1230048 次锅风,每次調(diào)用花費(fèi) 112.9 納秒酥诽。如果想讓測(cè)試運(yùn)行的時(shí)間更長(zhǎng),可以通過(guò) -benchtime= 指定皱埠,比如-benchtime=3s肮帐,表示執(zhí)行3秒。

image-20210715114940049

但是我們經(jīng)過(guò)測(cè)試發(fā)現(xiàn),測(cè)試1s和3s好像沒(méi)啥明顯區(qū)別训枢,實(shí)際上最終性能并沒(méi)有多大變化托修。一般來(lái)說(shuō)不需要太長(zhǎng),常用1s恒界、3s睦刃、5s即可,也可忙根據(jù)業(yè)務(wù)場(chǎng)景來(lái)判斷十酣。

1.2 并行用法

func BenchmarkSprints(b *testing.B) {
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            // do something
            fmt.Sprint("代碼軼事")
        }
    })
}
  • RunParallel并發(fā)的執(zhí)行benchmark涩拙。RunParallel創(chuàng)建p個(gè)goroutine然后把b.N個(gè)迭代測(cè)試分布到這些goroutine上。

  • goroutine的數(shù)目默認(rèn)是GOMAXPROCS婆誓。如果要增加non-CPU-bound的benchmark的并個(gè)數(shù)吃环,在執(zhí)行RunParallel之前那就使用b.SetParallelism(p int)來(lái)設(shè)置,最終goroutine個(gè)數(shù)就等于p * runtime.GOMAXPROCS(0)洋幻,郁轻。

numProcs := b.parallelism * runtime.GOMAXPROCS(0)
  • 所以并行的用法比較適合IO密集型的測(cè)試對(duì)象。

1.3 性能對(duì)比

上面是簡(jiǎn)單寫的幾個(gè)示例文留,下面使用我前面的文章Go語(yǔ)言幾種字符串的拼接方式比較里面關(guān)于字符串拼接的例子進(jìn)行示例:

// 文中全局有一個(gè)StrData變量好唯,是一個(gè)200長(zhǎng)度的字符串slice
// 直接使用“+”號(hào)拼接
func BenchmarkStringsAdd(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        var s string
        for _, v := range StrData {
            s += v
        }
    }
    b.StopTimer()

}
// fmt.Sprint拼接
func BenchmarkStringsFmt(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        var _ string = fmt.Sprint(StrData)
    }
    b.StopTimer()
}
// strings.Join拼接
func BenchmarkStringsJoin(b *testing.B) {
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        _ = strings.Join(StrData, "")
    }
    b.StopTimer()
}
// StringsBuffer拼接
func BenchmarkStringsBuffer(b *testing.B) {
    b.ResetTimer()

    for i := 0; i < b.N; i++ {
        n := len("") * (len(StrData) - 1)
        for i := 0; i < len(StrData); i++ {
            n += len(StrData[i])
        }
        var s bytes.Buffer
        s.Grow(n)
        for _, v := range StrData {
            s.WriteString(v)
        }
        _ = s.String()
    }

    b.StopTimer()
}
// 使用strings包里的builder類型拼接
func BenchmarkStringsBuilder(b *testing.B) {
    b.ResetTimer()

    for i := 0; i < b.N; i++ {
        n := len("") * (len(StrData) - 1)
        for i := 0; i < len(StrData); i++ {
            n += len(StrData[i])
        }

        var b strings.Builder
        b.Grow(n)
        b.WriteString(StrData[0])
        for _, s := range StrData[1:] {
            b.WriteString("")
            b.WriteString(s)
        }
        _ = b.String()
    }
    b.StopTimer()
}

這次我們添加-benchmem參數(shù),go test -bench=. -benchmem -run=none燥翅,來(lái)查看每次操作分配內(nèi)存的次數(shù)骑篙,運(yùn)行后的結(jié)果如下:

image-20210715214559725

從測(cè)試結(jié)果來(lái)看,strings包的Builder類型的效率是最高的森书,單次耗時(shí)最低靶端,內(nèi)存分配的次數(shù)最少,每次分配的內(nèi)存最低凛膏。這樣我們就能從測(cè)試結(jié)果看出來(lái)是那部分代碼最慢杨名、內(nèi)存分配占用太高,進(jìn)而想辦法對(duì)相應(yīng)的代碼進(jìn)行優(yōu)化處理猖毫。

在代碼開(kāi)發(fā)中台谍,我們很多時(shí)候是不需要太在乎性能的,但絕大部分時(shí)候是需要要求性能很高的吁断,因此編寫基準(zhǔn)測(cè)試就變得非常重要趁蕊。這能幫助我們開(kāi)發(fā)出高性能、高效率的代碼仔役。

1.4 結(jié)合pprof和火焰圖查看代碼性能

我們還是以1.3節(jié)的例子掷伙,以及Go語(yǔ)言幾種字符串的拼接方式比較里的例子來(lái)說(shuō)明一下benchmark結(jié)合pprof和火焰圖查看代碼性能的問(wèn)題。

需要先采集數(shù)據(jù)骂因,生成文件炎咖,然后用pprof打開(kāi)文件并已http的方式查看,可以分別采集內(nèi)存維度和CPU維度的數(shù)據(jù),具體命令如下:

# 使用benchmark采集3秒的內(nèi)存維度的數(shù)據(jù)乘盼,并生成文件
go test -bench=. -benchmem  -benchtime=3s -memprofile=mem_profile.out
# 采集CPU維度的數(shù)據(jù)
go test -bench=. -benchmem  -benchtime=3s -cpuprofile=cpu_profile.out
# 查看pprof文件升熊,指定http方式查看
go tool pprof -http="127.0.0.1:8080" mem_profile.out
go tool pprof -http="127.0.0.1:8080" cpu_profile.out
# 查看pprof文件,直接在命令行查看
go tool pprof mem_profile.out

我們執(zhí)行go tool pprof -http="127.0.0.1:8080" cpu_profile.out命令后绸栅,會(huì)自動(dòng)使用我們電腦的默認(rèn)瀏覽器打開(kāi):http://127.0.0.1:8080/ui/地址级野,會(huì)顯示默認(rèn)的Graph選項(xiàng)卡,顯示各方法間的調(diào)用關(guān)系:

image-20210719204704729

圖片不清楚粹胯,主要表達(dá)意思蓖柔,具體內(nèi)容可根據(jù)自己的測(cè)試情況進(jìn)行查看分析。

然后我們選擇左上角的菜單 VIEW->Flame Graph即可顯示火焰圖:

image-20210719205603278
image-20210719205629436

這里如果有的小伙伴沒(méi)有提前安裝好gvedit风纠,可能會(huì)報(bào)錯(cuò)提示需要安裝graphviz况鸣。Mac或Linux用戶可直接使用brew進(jìn)行安裝:

# Mac 安裝
brew install graphviz
# Ubuntu apt-get 安裝
sudo apt-get install graphviz
# yum 安裝
sudo yum install graphviz

Windows用戶去官網(wǎng)下載http://www.graphviz.org/download/

我們也可以直接在命令行使用go tool pprof cpu_profile.out命令進(jìn)行查看,

image-20210719210835542

比如上圖就是用命令行打開(kāi)竹观,然后輸入top3命令來(lái)返回消耗資源最多的3個(gè)函數(shù)镐捧,然后你也可以輸入help命令來(lái)查看支持的功能。

還有其它各種維度的指標(biāo)和命令就不在此處多說(shuō)了臭增,后面也會(huì)出pprof的文章懂酱。

上面介紹了使用benchmark進(jìn)行一個(gè)基準(zhǔn)測(cè)試的一些基礎(chǔ)用法, 當(dāng)然了誊抛,如果你比較卷列牺,還是可以繼續(xù)往下看,我們來(lái)介紹一些進(jìn)階的用法拗窃。

2 深入研究benchmark

下面的內(nèi)容瞎领,將會(huì)對(duì)一些不常用但是很深入的內(nèi)容做一些說(shuō)明,有很多方法我也幾乎用不到随夸,如有不對(duì)的地方還請(qǐng)留言指正默刚,感謝!

2.1 Start/Stop/ResetTimer()

這三個(gè)方法都是針對(duì)計(jì)時(shí)統(tǒng)計(jì)器內(nèi)存統(tǒng)計(jì)器操作的逃魄。

因?yàn)橛行┣闆r我們?cè)谧鯾enchmark測(cè)試的時(shí)候,是不想將一些不關(guān)心的工作耗時(shí)計(jì)算進(jìn)benchmark結(jié)果中的澜搅。

比如我在1.3節(jié)中做出的示例伍俘,其實(shí)我在最開(kāi)始的init()函數(shù)里設(shè)置了一個(gè)較大的slice:StrData。以便在全局使用同一個(gè)slice進(jìn)行測(cè)試勉躺,但是我在設(shè)置這個(gè)較大的slice的時(shí)候也會(huì)內(nèi)存的消耗和工作耗時(shí)癌瘾,但是我并不關(guān)心它的資源消耗,因此我也不希望會(huì)對(duì)benchmark的測(cè)試結(jié)果產(chǎn)生影響饵溅,所以在每個(gè)被測(cè)單元里都執(zhí)行了b.ResetTimer()妨退。

而且需要注意的是,在并行的情況下,b.ResetTimer()需要在b.RunParallel()之前調(diào)用咬荷,如:

func BenchmarkSprints(b *testing.B) {
  
  b.ResetTimer()
  
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            // do something
            fmt.Sprint("代碼軼事")
        }
    })
}

StopTimer()StartTimer()的用法如下:

init();
b.ResetTimer()
for i := 0; i < b.N; i++ {
  flag := func1()
  if flag {
    // 需要計(jì)時(shí)
    b.StartTimer()
  }else {
    // 不需要計(jì)時(shí)
    b.StopTimer()
  }
}

總結(jié)來(lái)說(shuō)

  • StartTimer:開(kāi)始計(jì)時(shí)測(cè)試冠句,該函數(shù)會(huì)被自動(dòng)調(diào)用,也可用于在調(diào)用了StopTimer后恢復(fù)計(jì)時(shí)幸乒;
  • StopTimer:停止對(duì)測(cè)試計(jì)時(shí)懦底,也可用于在執(zhí)行復(fù)雜的初始化時(shí)暫停計(jì)時(shí);
  • ResetTimer:將已用的基準(zhǔn)時(shí)間和內(nèi)存分配計(jì)數(shù)器置零罕扎,并刪除相關(guān)指標(biāo)聚唐,但不影響計(jì)時(shí)器是否在運(yùn)行;

2.2 benchmark的輸出項(xiàng)目含義解釋

我們先嘗試執(zhí)行go test -bench=. -benchmem得到下圖的輸出結(jié)果:

image-20210721201359445

接下來(lái)分別介紹每一項(xiàng)的含義腔召;

  1. 第一項(xiàng)是現(xiàn)實(shí)的被測(cè)試的方法名杆查,后面跟的“-8”表示P的個(gè)數(shù),通過(guò)在命令后面追加參數(shù)“-cpu 4,8” 來(lái)指定臀蛛;
  2. 第二項(xiàng)是指在b.N周期內(nèi)迭代的總次數(shù)亲桦,即b.N的執(zhí)行上限,通常程序執(zhí)行效率越高掺栅,耗時(shí)越低烙肺,內(nèi)存分配和消耗越小,迭代次數(shù)就越大氧卧;
  3. b.N每次迭代耗時(shí)桃笙,單位是ns,即每次迭代消耗多少ns沙绝,是一個(gè)被平均后的均值搏明;
  4. b.N每次迭代的內(nèi)存分配,即在每次迭代中分配了多少字節(jié)的內(nèi)存闪檬;
  5. b.N每次迭代所觸發(fā)的內(nèi)存分配次數(shù)星著,觸發(fā)的內(nèi)存分配次數(shù)越大,耗時(shí)多大粗悯,效率也就越低虚循;

2.3 進(jìn)階參數(shù)

2.3.1 -benchtime t

我們?cè)跍y(cè)試某個(gè)函數(shù)性能的時(shí)候,并不是每次執(zhí)行都會(huì)得到一模一樣的效果样傍,我連續(xù)執(zhí)行10次横缔,可能會(huì)有10次不一樣的結(jié)果,這時(shí)候我們可能會(huì)選擇添加一個(gè)指定的采樣時(shí)間衫哥,來(lái)得出一個(gè)平均值茎刚,在上文中我們討論benchmark結(jié)合pprof使用的時(shí)候就用到了這個(gè)參數(shù),但也不是盲目的無(wú)限增加采樣時(shí)間就是好的撤逢,通常采用3秒5秒即可膛锭。

image-20210721205642250

該參數(shù)還可支持特殊形式Nx粮坞,用來(lái)指定被測(cè)函數(shù)的迭代次數(shù),如:

image-20210721205601441

從上圖可以看出初狰,指定了迭代100次莫杈,則每個(gè)函數(shù)都會(huì)只迭代100次。

2.3.2 -count n

為了我們測(cè)試的準(zhǔn)確性跷究,可以添加-count來(lái)指定測(cè)試:

image-20210721210325676

2.3.3 -cpu n

還可以指定cpu的核數(shù)姓迅,比如我下面的這個(gè)例子,使用遞歸實(shí)現(xiàn)一個(gè)計(jì)算斐波那契數(shù)列的方法俊马,然后每次迭代都開(kāi)啟10個(gè)goroutine丁存,并且要等這10個(gè)goroutine都執(zhí)行結(jié)束后才會(huì)進(jìn)行下一次迭代,代碼如下:

func BenchmarkFibonacci(b *testing.B) {
    b.ResetTimer()

    for i := 0; i < b.N; i++ {
        wg := sync.WaitGroup{}
        wg.Add(10)
        for i := 0; i < 10; i++ {
            go func(wg1 *sync.WaitGroup) {
                defer wg1.Done()
                arr := [20]int{}
                for i := 0; i < 20; i++ {
                    arr[i] = fibonacci(i)
                }
            }(&wg)
        }
    }
}

func fibonacci(n int) (res int) {
    if n <= 1 {
        res = 1
    } else {
        res = fibonacci(n-1) + fibonacci(n-2)
    }
    return
}

然后分別指定-cpu=1,2,4,6,8,10來(lái)查看測(cè)試結(jié)果:

image-20210721211951326

從運(yùn)行結(jié)果來(lái)看柴我,CPU核心數(shù)提高對(duì)性能有一定影響解寝,但也無(wú)法一直實(shí)現(xiàn)正相關(guān),而且超過(guò)一定閾值后反而性能下降了艘儒,因?yàn)镃PU核心的切換也需要成本聋伦。因此也不能盲目提高CPU核心數(shù)。

2.3.4 -benchmark

除了速度界睁,內(nèi)存分配也是一個(gè)很重要的指標(biāo)觉增,我在Go語(yǔ)言幾種字符串的拼接方式比較一文中做個(gè)比較,在使用strings包的builder類型去做字符串拼接的時(shí)候翻斟,是否合理的預(yù)分配內(nèi)存逾礁,測(cè)試的結(jié)果是不同的,如果我們能合理的預(yù)分配內(nèi)存访惜,那么性能也會(huì)有較大的提升嘹履。下面我再貼出一個(gè)例子來(lái)看實(shí)際的效果:

// 根據(jù)slice的長(zhǎng)度,對(duì)strings.Builder進(jìn)行預(yù)分配內(nèi)存
func BenchmarkStringsBuilder1(b *testing.B) {
    b.ResetTimer()

    for i := 0; i < b.N; i++ {
        n := len("") * (len(StrData) - 1)
        for i := 0; i < len(StrData); i++ {
            n += len(StrData[i])
        }

        var b strings.Builder
        b.Grow(n)
        b.WriteString(StrData[0])
        for _, s := range StrData[1:] {
            b.WriteString("")
            b.WriteString(s)
        }
        _ = b.String()
    }
    b.StopTimer()
}
// 不進(jìn)行預(yù)分配內(nèi)存
func BenchmarkStringsBuilder2(b *testing.B) {
    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        var b strings.Builder
        b.WriteString(StrData[0])
        for _, s := range StrData[1:] {
            b.WriteString("")
            b.WriteString(s)
        }
        _ = b.String()
    }
    b.StopTimer()
}

然后使用benchmark測(cè)試债热,查看結(jié)果:

image-20210721215534206

BenchmarkStringsBuilder1是進(jìn)行了合理的預(yù)分配內(nèi)存砾嫉,BenchmarkStringsBuilder2沒(méi)有進(jìn)行預(yù)分配內(nèi)存,從測(cè)試的結(jié)果可以看出窒篱,BenchmarkStringsBuilder1的執(zhí)行效率比BenchmarkStringsBuilder2的執(zhí)行效率高了特別多焕刮。

3 benchmark原理

要討論benchmark基準(zhǔn)測(cè)試的原理,就要討論testing.B的數(shù)據(jù)結(jié)構(gòu)墙杯,還要分析b.N的值济锄,雖然官方資料中說(shuō)b.N的值會(huì)自動(dòng)調(diào)整,以保證可靠的計(jì)時(shí)霍转,但仍需分析其實(shí)現(xiàn)的機(jī)制。

那么我們拋出以下問(wèn)題:

  • b.N是如何自動(dòng)調(diào)整的一汽?
  • 內(nèi)存統(tǒng)計(jì)是如何實(shí)現(xiàn)的?
  • SetBytes()其使用場(chǎng)景是什么醋安?

原理部分的討論參考了【Go專家編程】的一些文章采驻,可以點(diǎn)擊關(guān)鍵詞去看在線版本。

3.1 testing.B的數(shù)據(jù)結(jié)構(gòu)

源碼包src/testing/benchmark.go:B定義了性能測(cè)試的數(shù)據(jù)結(jié)構(gòu)恕沫,我們提取其比較重要的一些成員進(jìn)行分析:

type B struct {
    common           // 與testing.T共享的testing.common,負(fù)責(zé)記錄日志纱意、狀態(tài)等婶溯,詳情可見(jiàn)src/testing/testing.go文件,在大概385行
    importPath       string // import path of the package containing the benchmark
    context          *benchContext
    N                int            // 目標(biāo)代碼執(zhí)行次數(shù)偷霉,會(huì)自動(dòng)調(diào)整
    previousN        int           // number of iterations in the previous run
    previousDuration time.Duration // total duration of the previous run
    benchFunc        func(b *B)   // 性能測(cè)試函數(shù)
    benchTime        time.Duration // 性能測(cè)試函數(shù)最少執(zhí)行的時(shí)間迄委,默認(rèn)為1s,可以通過(guò)參數(shù)'-benchtime 10s'指定
    bytes            int64         // 每次迭代處理的字節(jié)數(shù)
    missingBytes     bool // one of the subbenchmarks does not have bytes set.
    timerOn          bool // 是否已開(kāi)始計(jì)時(shí)
    showAllocResult  bool
    result           BenchmarkResult // 測(cè)試結(jié)果
    parallelism      int // RunParallel creates parallelism*GOMAXPROCS goroutines
    // The initial states of memStats.Mallocs and memStats.TotalAlloc.
    startAllocs uint64  // 計(jì)時(shí)開(kāi)始時(shí)堆中分配的對(duì)象總數(shù)
    startBytes  uint64  // 計(jì)時(shí)開(kāi)始時(shí)時(shí)堆中分配的字節(jié)總數(shù)
    // The net total of this test after being run.
    netAllocs uint64 // 計(jì)時(shí)結(jié)束時(shí)类少,堆中增加的對(duì)象總數(shù)
    netBytes  uint64 // 計(jì)時(shí)結(jié)束時(shí)叙身,堆中增加的字節(jié)總數(shù)
    extra map[string]float64 // 額外收集的指標(biāo)
}

其主要成員如下:

  • common: 與testing.T共享的testing.common,管理著日志硫狞、狀態(tài)等信轿;
  • N:每個(gè)測(cè)試中用戶代碼執(zhí)行次數(shù)
  • benchFunc:測(cè)試函數(shù)
  • benchTime:性能測(cè)試最少執(zhí)行時(shí)間,默認(rèn)為1s残吩,可以通過(guò)能數(shù)-benchtime 2s指定
  • bytes:每次迭代處理的字節(jié)數(shù)
  • timerOn:計(jì)時(shí)啟動(dòng)標(biāo)志财忽,默認(rèn)為false,啟動(dòng)計(jì)時(shí)為true
  • startAllocs:測(cè)試啟動(dòng)時(shí)記錄堆中分配的對(duì)象數(shù)
  • startBytes:測(cè)試啟動(dòng)時(shí)記錄堆中分配的字節(jié)數(shù)
  • netAllocs:測(cè)試結(jié)束后記錄堆中新增加的對(duì)象數(shù)泣侮,公式:結(jié)束時(shí)堆中分配的對(duì)象數(shù)-
  • netBytes:測(cè)試對(duì)事后記錄堆中新增加的字節(jié)數(shù)

流程示意圖如下

image-20210813220358309

5 參考文獻(xiàn)

https://books.studygolang.com/GoExpertProgramming/chapter07/7.3.4-benchmark.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末即彪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子旁瘫,更是在濱河造成了極大的恐慌祖凫,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酬凳,死亡現(xiàn)場(chǎng)離奇詭異惠况,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)宁仔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門稠屠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人翎苫,你說(shuō)我怎么就攤上這事权埠。” “怎么了煎谍?”我有些...
    開(kāi)封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵攘蔽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我呐粘,道長(zhǎng)满俗,這世上最難降的妖魔是什么转捕? 我笑而不...
    開(kāi)封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮唆垃,結(jié)果婚禮上五芝,老公的妹妹穿的比我還像新娘。我一直安慰自己辕万,他們只是感情好枢步,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著渐尿,像睡著了一般醉途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涡戳,一...
    開(kāi)封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天结蟋,我揣著相機(jī)與錄音,去河邊找鬼渔彰。 笑死嵌屎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的恍涂。 我是一名探鬼主播宝惰,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼再沧!你這毒婦竟也來(lái)了尼夺?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炒瘸,失蹤者是張志新(化名)和其女友劉穎淤堵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體顷扩,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拐邪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隘截。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扎阶。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖婶芭,靈堂內(nèi)的尸體忽然破棺而出东臀,到底是詐尸還是另有隱情,我是刑警寧澤犀农,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布惰赋,位于F島的核電站,受9級(jí)特大地震影響呵哨,放射性物質(zhì)發(fā)生泄漏赁濒。R本人自食惡果不足惜贵扰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望流部。 院中可真熱鬧,春花似錦纹坐、人聲如沸枝冀。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)果漾。三九已至,卻和暖如春谷誓,著一層夾襖步出監(jiān)牢的瞬間绒障,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工捍歪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留户辱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓糙臼,卻偏偏與公主長(zhǎng)得像庐镐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子变逃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容