5702a89db6
Since we don't need the actual split values, instead of calling `strings.Split`, which allocates new slices on each call, use `strings.Index`. This significantly reduces the allocations required when doing env value replacements. Additionally, pre-allocate the env var slice, even if we allocate a little more than we need, it keeps us from having to do multiple allocations while appending. ``` benchmark old ns/op new ns/op delta BenchmarkReplaceOrAppendEnvValues/0-8 486 313 -35.60% BenchmarkReplaceOrAppendEnvValues/100-8 10553 1535 -85.45% BenchmarkReplaceOrAppendEnvValues/1000-8 94275 12758 -86.47% BenchmarkReplaceOrAppendEnvValues/10000-8 1161268 129269 -88.87% benchmark old allocs new allocs delta BenchmarkReplaceOrAppendEnvValues/0-8 5 2 -60.00% BenchmarkReplaceOrAppendEnvValues/100-8 110 0 -100.00% BenchmarkReplaceOrAppendEnvValues/1000-8 1013 0 -100.00% BenchmarkReplaceOrAppendEnvValues/10000-8 10022 0 -100.00% benchmark old bytes new bytes delta BenchmarkReplaceOrAppendEnvValues/0-8 192 24 -87.50% BenchmarkReplaceOrAppendEnvValues/100-8 7360 0 -100.00% BenchmarkReplaceOrAppendEnvValues/1000-8 64832 0 -100.00% BenchmarkReplaceOrAppendEnvValues/10000-8 1146049 0 -100.00% ``` Signed-off-by: Brian Goff <cpuguy83@gmail.com>
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
package container // import "github.com/docker/docker/container"
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"testing"
|
|
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestReplaceAndAppendEnvVars(t *testing.T) {
|
|
var (
|
|
d = []string{"HOME=/", "FOO=foo_default"}
|
|
// remove FOO from env
|
|
// remove BAR from env (nop)
|
|
o = []string{"HOME=/root", "TERM=xterm", "FOO", "BAR"}
|
|
)
|
|
|
|
env := ReplaceOrAppendEnvValues(d, o)
|
|
t.Logf("default=%v, override=%v, result=%v", d, o, env)
|
|
if len(env) != 2 {
|
|
t.Fatalf("expected len of 2 got %d", len(env))
|
|
}
|
|
if env[0] != "HOME=/root" {
|
|
t.Fatalf("expected HOME=/root got '%s'", env[0])
|
|
}
|
|
if env[1] != "TERM=xterm" {
|
|
t.Fatalf("expected TERM=xterm got '%s'", env[1])
|
|
}
|
|
}
|
|
|
|
func BenchmarkReplaceOrAppendEnvValues(b *testing.B) {
|
|
b.Run("0", func(b *testing.B) {
|
|
benchmarkReplaceOrAppendEnvValues(b, 0)
|
|
})
|
|
b.Run("100", func(b *testing.B) {
|
|
benchmarkReplaceOrAppendEnvValues(b, 100)
|
|
})
|
|
b.Run("1000", func(b *testing.B) {
|
|
benchmarkReplaceOrAppendEnvValues(b, 1000)
|
|
})
|
|
b.Run("10000", func(b *testing.B) {
|
|
benchmarkReplaceOrAppendEnvValues(b, 10000)
|
|
})
|
|
}
|
|
|
|
func benchmarkReplaceOrAppendEnvValues(b *testing.B, extraEnv int) {
|
|
b.StopTimer()
|
|
// remove FOO from env
|
|
// remove BAR from env (nop)
|
|
o := []string{"HOME=/root", "TERM=xterm", "FOO", "BAR"}
|
|
|
|
if extraEnv > 0 {
|
|
buf := make([]byte, 5)
|
|
for i := 0; i < extraEnv; i++ {
|
|
n, err := rand.Read(buf)
|
|
assert.NilError(b, err)
|
|
key := string(buf[:n])
|
|
|
|
n, err = rand.Read(buf)
|
|
assert.NilError(b, err)
|
|
val := string(buf[:n])
|
|
|
|
o = append(o, key+"="+val)
|
|
}
|
|
}
|
|
d := make([]string, 0, len(o)+2)
|
|
d = append(d, []string{"HOME=/", "FOO=foo_default"}...)
|
|
|
|
b.StartTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = ReplaceOrAppendEnvValues(d, o)
|
|
}
|
|
}
|