mirror of
https://github.com/burrowers/garble.git
synced 2026-04-22 23:57:14 +08:00
store name pairs for _realName as a slice of pairs
Iterating over a map is much more expensive than iterating over a slice,
given how it needs to work out which keys are present in each bucket
and then randomize the order in which to navigate the keys.
None of this work needs to happen when iterating over a slice.
A map would be nice if we were to actually do map lookups, but we don't.
│ old │ new │
│ sec/op │ sec/op vs base │
AbiRealName-8 707.1µ ± 1% 196.7µ ± 1% -72.17% (p=0.001 n=7)
│ old │ new │
│ B/s │ B/s vs base │
AbiRealName-8 517.6Ki ± 2% 1816.4Ki ± 1% +250.94% (p=0.001 n=7)
│ old │ new │
│ B/op │ B/op vs base │
AbiRealName-8 5.362Ki ± 0% 5.359Ki ± 0% -0.05% (p=0.001 n=7)
│ old │ new │
│ allocs/op │ allocs/op vs base │
AbiRealName-8 19.00 ± 0% 19.00 ± 0% ~ (p=1.000 n=7) ¹
This commit is contained in:
+16
-7
@@ -7,12 +7,11 @@ import (
|
||||
_ "embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math/rand/v2"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -170,18 +169,28 @@ func BenchmarkBuild(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkAbiRealName(b *testing.B) {
|
||||
// Benchmark two thousand obfuscated names in _nameMap
|
||||
// Benchmark two thousand obfuscated names in _realNamePairs
|
||||
// and a variety of input strings to reverse.
|
||||
// As an example, the cmd/go binary ends up with about 2200 entries
|
||||
// in _nameMap as of November 2024, so it's a realistic figure.
|
||||
// in _realNamePairs as of November 2024, so it's a realistic figure.
|
||||
// Structs with tens of fields are also relatively normal.
|
||||
salt := []byte("some salt bytes")
|
||||
for n := range 2000 {
|
||||
name := fmt.Sprintf("name_%d", n)
|
||||
garbled := hashWithCustomSalt(salt, name)
|
||||
_nameMap[garbled] = name
|
||||
_realNamePairs = append(_realNamePairs, [2]string{garbled, name})
|
||||
}
|
||||
chosen := slices.Sorted(maps.Keys(_nameMap))[:20]
|
||||
// Pick twenty names at random to use as inputs below.
|
||||
// Use a deterministic random source so it's stable between benchmark runs.
|
||||
rnd := rand.New(rand.NewPCG(1, 2))
|
||||
var chosen []string
|
||||
for _, pair := range _realNamePairs {
|
||||
chosen = append(chosen, pair[0])
|
||||
}
|
||||
rnd.Shuffle(len(chosen), func(i, j int) {
|
||||
chosen[i], chosen[j] = chosen[j], chosen[i]
|
||||
})
|
||||
chosen = chosen[:20]
|
||||
|
||||
inputs := []string{
|
||||
// non-obfuscated names and types
|
||||
@@ -214,5 +223,5 @@ func BenchmarkAbiRealName(b *testing.B) {
|
||||
}
|
||||
}
|
||||
})
|
||||
_nameMap = map[string]string{}
|
||||
_realNamePairs = [][2]string{}
|
||||
}
|
||||
|
||||
+4
-2
@@ -39,7 +39,9 @@ func _realName(name string) string {
|
||||
}
|
||||
remLen := len(name[i:])
|
||||
found := false
|
||||
for obfName, real := range _nameMap {
|
||||
for _, pair := range _realNamePairs {
|
||||
obfName := pair[0]
|
||||
real := pair[1]
|
||||
keyLen := len(obfName)
|
||||
if remLen < keyLen {
|
||||
continue
|
||||
@@ -58,4 +60,4 @@ func _realName(name string) string {
|
||||
return name
|
||||
}
|
||||
|
||||
var _nameMap = map[string]string{}
|
||||
var _realNamePairs = [][2]string{}
|
||||
|
||||
@@ -58,13 +58,13 @@ func reflectMainPrePatch(path string) ([]byte, error) {
|
||||
// reflectMainPostPatch populates the name mapping with the final obfuscated->real name
|
||||
// mappings after all packages have been analyzed.
|
||||
func reflectMainPostPatch(file []byte, lpkg *listedPackage, pkg pkgCache) []byte {
|
||||
obfMapName := hashWithPackage(lpkg, "_nameMap")
|
||||
nameMap := fmt.Sprintf("%s = map[string]string{", obfMapName)
|
||||
obfVarName := hashWithPackage(lpkg, "_realNamePairs")
|
||||
nameMap := fmt.Sprintf("%s = [][2]string{", obfVarName)
|
||||
|
||||
var b strings.Builder
|
||||
keys := slices.Sorted(maps.Keys(pkg.ReflectObjectNames))
|
||||
for _, obf := range keys {
|
||||
b.WriteString(fmt.Sprintf(`"%s": "%s",`, obf, pkg.ReflectObjectNames[obf]))
|
||||
b.WriteString(fmt.Sprintf("{%q, %q},", obf, pkg.ReflectObjectNames[obf]))
|
||||
}
|
||||
|
||||
return bytes.Replace(file, []byte(nameMap), []byte(nameMap+b.String()), 1)
|
||||
|
||||
Reference in New Issue
Block a user