Skip to content

Commit

Permalink
pcvaluetab: benchmark multiple PCs, rejigger size reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
aclements committed Aug 18, 2023
1 parent c4baf15 commit b79a1c9
Showing 1 changed file with 63 additions and 31 deletions.
94 changes: 63 additions & 31 deletions pcvaluetab/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ package main

import (
"flag"
"fmt"
"math"
"math/rand"
"os"
"path/filepath"
"strings"
"sync"
"testing"
)

Expand Down Expand Up @@ -39,24 +42,36 @@ func BenchmarkDecode(b *testing.B) {
}

for _, bin := range flagBinary.list {
b.Run(filepath.Base(bin), func(b *testing.B) {
decode1(b, bin)
b.Run("bin="+filepath.Base(bin), func(b *testing.B) {
symtab := LoadSymTab(bin)

for _, pcMode := range []uint32{pcModeRandom, 0, 4096} {
label := fmt.Sprint(pcMode)
if pcMode == pcModeRandom {
label = "random"
}

b.Run("pc="+label, func(b *testing.B) {
decode1(b, symtab, pcMode)
})
}
if *flagSizeStats {
fileSizeStats(b, bin, symtab)
}
})
}
}

func decode1(b *testing.B, bin string) {
func fileSizeStats(b *testing.B, bin string, symtab *SymTab) {
var fileBytes int
if stat, err := os.Stat(bin); err != nil {
b.Fatal(err)
} else {
fileBytes = int(stat.Size())
}

symtab := LoadSymTab(bin)

var varintBytes, altBytes int
if *flagSizeStats {
gather := sync.OnceFunc(func() {
// Collect the total size of the varint and alt tables.
altDups := map[string]bool{}
for _, tab := range symtab.PCTabs {
Expand All @@ -70,8 +85,34 @@ func decode1(b *testing.B, bin string) {
altDups[string(altTab)] = true
altBytes += len(altTab)
}
}
})

// This is a bit goofy. We're not measuring time, so the normal testing.B
// looping doesn't work. We start a sub-benchmark so that -test.bench
// selection works, and then print out own result and call SkipNow to
// prevent looping. This hack means results won't align nicely, and if this
// this is the first "benchmark" to run, our results will appear before the
// benchmark tags.

b.Run("enc=varint", func(b *testing.B) {
gather()
fmt.Printf("%s\t%d\t%v table-bytes\t%v file-bytes\n", b.Name(), 1, varintBytes, fileBytes)
b.SkipNow()
})

b.Run("enc=alt", func(b *testing.B) {
gather()
altFileBytes := fileBytes - varintBytes + altBytes
fmt.Printf("%s\t%d\t%v table-bytes\t%v file-bytes\n", b.Name(), 1, altBytes, altFileBytes)
// Metrics get kind of weird with "percent change", so just log it.
fmt.Printf("file-bytes alt versus varint: %+f%%\n", diffPct(fileBytes, altFileBytes))
b.SkipNow()
})
}

const pcModeRandom = math.MaxUint32

func decode1(b *testing.B, symtab *SymTab, pcMode uint32) {
// Random sample of tables.
const nSamples = 1024
type sample struct {
Expand All @@ -80,32 +121,34 @@ func decode1(b *testing.B, bin string) {
textLen uint32
pc uint32
}
samples := make([]sample, nSamples)
for i := range samples {
samples := make([]sample, 0, nSamples)
for len(samples) < nSamples {
// Pick a random table.
var tab *VarintPCData
for _, tab = range symtab.PCTabs {
break
}
// Pick a PC.
pc := pcMode
if pcMode == math.MaxUint32 {
pc = uint32(rand.Intn(int(tab.TextLen)))
} else if pc >= tab.TextLen {
// Try again
continue
}
// Re-encode it.
altTab := linearIndex(tab)
// Pick a random PC.
pc := uint32(rand.Intn(int(tab.TextLen)))

samples[i] = sample{tab, altTab, tab.TextLen, pc}
samples = append(samples, sample{tab, altTab, tab.TextLen, pc})
}

b.Run("varint", func(b *testing.B) {
b.Run("enc=varint", func(b *testing.B) {
for i := 0; i < b.N; i++ {
sample := &samples[i%len(samples)]
lookupVarintPCData(sample.varintTab.Raw, uintptr(sample.pc), nil)
}
if *flagSizeStats {
b.ReportMetric(float64(varintBytes), "table-bytes")
b.ReportMetric(float64(fileBytes), "file-bytes")
}
})
b.Run("varint-cache-nohit", func(b *testing.B) {
b.Run("enc=varint/cachehit=0", func(b *testing.B) {
var cache pcvalueCache
for i := 0; i < b.N; i++ {
// In practice this will never hit in the cache because there
Expand All @@ -114,7 +157,7 @@ func decode1(b *testing.B, bin string) {
lookupVarintPCData(sample.varintTab.Raw, uintptr(sample.pc), &cache)
}
})
b.Run("varint-cache-hit", func(b *testing.B) {
b.Run("enc=varint/cachehit=7:1", func(b *testing.B) {
var cache pcvalueCache
for i := 0; i < b.N; i++ {
// Hit 7 times out of 8. That's probably dramatically higher
Expand All @@ -123,21 +166,10 @@ func decode1(b *testing.B, bin string) {
lookupVarintPCData(sample.varintTab.Raw, uintptr(sample.pc), &cache)
}
})
first := true
b.Run("alt", func(b *testing.B) {
b.Run("enc=alt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
sample := &samples[i%len(samples)]
lookupLinearIndex(sample.altTab, sample.textLen, sample.pc)
}
if *flagSizeStats {
b.ReportMetric(float64(altBytes), "table-bytes")
altFileBytes := fileBytes - varintBytes + altBytes
b.ReportMetric(float64(altFileBytes), "file-bytes")
if first {
// Metrics get kind of weird with "percent change", so just log it.
b.Logf("file-bytes change versus varint: %+f%%", diffPct(fileBytes, altFileBytes))
first = false
}
}
})
}

0 comments on commit b79a1c9

Please sign in to comment.