Last active
November 7, 2021 20:16
-
-
Save thockin/8fc599cc4adc7aba72a367057704a798 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"testing" | |
) | |
// | |
// Baseline perf for single operations | |
// | |
func BenchmarkOneAppend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
write(buf, append(a, "these", "are")...) | |
if buf.String() != "a few of my favorite things these are" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneVariadic(b *testing.B) { | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
write(buf, "these", "are", "a", "few", "of", "my", "favorite", "things") | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOnePrepend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
write(buf, prepend(a, "these", "are")...) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneSG(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
writeSG(buf, []string{"these", "are"}, a) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneIntf(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
writeIntf(buf, "these", "are", a) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
// | |
// More representative patterns. Each of these should illustrate how c9ode | |
// looks for: | |
// * inline args (all specified in one place) | |
// * accumulated args, where the chain is known up-front | |
// * accumulated args, where the chain is known at the end | |
// | |
func BenchmarkReprSGMinSlices(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeSG(buf, []string{ | |
"-A", "CHAIN", | |
"-m", protocol, "-p", protocol, | |
"-d", ip, "--dport", port, | |
"-j", "FOOBAR", | |
}) | |
// Accumulate args, chain is known. | |
a = append(a[:0], "-A", "CHAIN") | |
a = append(a, "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeSG(buf, a) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeSG(buf, []string{"-A", "CHAIN"}, a) | |
} | |
} | |
func BenchmarkReprSGMinSlicesHelpers(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
// NB: We can't unpack these slices | |
writeSG(buf, | |
appendFunc("CHAIN"), | |
protocolFunc(protocol), | |
destFunc(ip, port), | |
jumpFunc("FOOBAR"), | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], appendFunc("CHAIN")...) | |
a = append(a, protocolFunc(protocol)...) | |
a = append(a, destFunc(ip, port)...) | |
a = append(a, jumpFunc("FOOBAR")...) | |
writeSG(buf, a) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], protocolFunc(protocol)...) | |
a = append(a, destFunc(ip, port)...) | |
a = append(a, jumpFunc("FOOBAR")...) | |
writeSG(buf, appendFunc("CHAIN"), a) | |
} | |
} | |
func BenchmarkReprSGManySlices(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeSG(buf, | |
[]string{"-A", "CHAIN"}, | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}, | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], []string{"-A", "CHAIN"}) | |
a = append(a, []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
writeSG(buf, a...) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
writeSG(buf, append([][]string{{"-A", "CHAIN"}}, a...)...) | |
} | |
} | |
func BenchmarkReprSGManySlicesHelpers(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeSG(buf, | |
appendFunc("CHAIN"), | |
protocolFunc(protocol), | |
destFunc(ip, port), | |
jumpFunc("FOOBAR"), | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], appendFunc("CHAIN")) | |
a = append(a, protocolFunc(protocol)) | |
a = append(a, destFunc(ip, port)) | |
a = append(a, jumpFunc("FOOBAR")) | |
writeSG(buf, a...) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], protocolFunc(protocol)) | |
a = append(a, destFunc(ip, port)) | |
a = append(a, jumpFunc("FOOBAR")) | |
writeSG(buf, append([][]string{{"-A", "CHAIN"}}, a...)...) | |
} | |
} | |
func BenchmarkReprIntfMinSlices(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeIntf(buf, | |
"-A", "CHAIN", | |
"-m", protocol, "-p", protocol, | |
"-d", ip, "--dport", port, | |
"-j", "FOOBAR", | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], "-A", "CHAIN") | |
a = append(a, "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeIntf(buf, a) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeIntf(buf, "-A", "CHAIN", a) | |
} | |
} | |
func BenchmarkReprIntfMinSlicesHelpers(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
// NB: We can't unpack these slices | |
writeIntf(buf, | |
appendFunc("CHAIN"), | |
protocolFunc(protocol), | |
destFunc(ip, port), | |
jumpFunc("FOOBAR"), | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], appendFunc("CHAIN")...) | |
a = append(a, protocolFunc(protocol)...) | |
a = append(a, destFunc(ip, port)...) | |
a = append(a, jumpFunc("FOOBAR")...) | |
writeIntf(buf, a) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], protocolFunc(protocol)...) | |
a = append(a, destFunc(ip, port)...) | |
a = append(a, jumpFunc("FOOBAR")...) | |
writeIntf(buf, appendFunc("CHAIN"), a) | |
} | |
} | |
func BenchmarkReprIntfManySlices(b *testing.B) { | |
a := make([]interface{}, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeIntf(buf, | |
[]string{"-A", "CHAIN"}, | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}, | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], []string{"-A", "CHAIN"}) | |
a = append(a, []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
writeIntf(buf, a...) | |
// Accumulate args, chain is late-bound. | |
a = append(a[:0], []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
writeIntf(buf, append([]interface{}{"-A", "CHAIN"}, a...)...) | |
} | |
} | |
func BenchmarkReprIntfManySlicesHelpers(b *testing.B) { | |
a := make([]interface{}, 0, 64) | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
// Inline args. | |
writeIntf(buf, | |
appendFunc("CHAIN"), | |
protocolFunc(protocol), | |
destFunc(ip, port), | |
jumpFunc("FOOBAR"), | |
) | |
// Accumulate args, chain is known. | |
a = append(a[:0], appendFunc("CHAIN")) | |
a = append(a, protocolFunc(protocol)) | |
a = append(a, destFunc(ip, port)) | |
a = append(a, jumpFunc("FOOBAR")) | |
writeIntf(buf, a...) | |
// Accumulate a series of slices (e.g. via helper functions) | |
a = append(a[:0], protocolFunc(protocol)) | |
a = append(a, destFunc(ip, port)) | |
a = append(a, jumpFunc("FOOBAR")) | |
writeIntf(buf, append([]interface{}{"-A", "CHAIN"}, a...)...) | |
} | |
} | |
func BenchmarkIntf(b *testing.B) { | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeIntf(buf, | |
"-A", "CHAIN", | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}) | |
} | |
} | |
func BenchmarkIntf2(b *testing.B) { | |
buf := bytes.NewBuffer(make([]byte, 0, 1024)) | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeIntf2(buf, | |
"-A", "CHAIN", | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}) | |
} | |
} | |
// go:noinline | |
func appendFunc(chain string) []string { | |
return []string{"-A", chain} | |
} | |
// go:noinline | |
func protocolFunc(proto string) []string { | |
return []string{"-m", proto, "-p", proto} | |
} | |
// go:noinline | |
func destFunc(ip, port string) []string { | |
return []string{"-d", ip, "--dport", port} | |
} | |
// go:noinline | |
func jumpFunc(chain string) []string { | |
return []string{"-j", chain} | |
} | |
// other code used in the above | |
func prepend(sl []string, args ...string) []string { | |
return append(args, sl...) | |
} | |
// go:noinline | |
func write(buf *bytes.Buffer, words ...string) { | |
for i, w := range words { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
buf.WriteString(w) | |
} | |
} | |
// go:noinline | |
func writeSG(buf *bytes.Buffer, phrases ...[]string) { | |
for i, p := range phrases { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
write(buf, p...) | |
} | |
} | |
// go:noinline | |
func writeIntf(buf *bytes.Buffer, parts ...interface{}) { | |
for i, p := range parts { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
switch x := p.(type) { | |
case string: | |
buf.WriteString(x) | |
case []string: | |
write(buf, x...) | |
default: | |
panic("huh?") | |
} | |
} | |
} | |
// go:noinline | |
func writeIntf2(buf *bytes.Buffer, parts ...interface{}) { | |
for i, p := range parts { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
switch x := p.(type) { | |
case string: | |
buf.WriteString(x) | |
case []string: | |
for i, p := range x { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
buf.WriteString(p) | |
} | |
default: | |
panic("huh?") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"testing" | |
) | |
// | |
// Baseline perf for single operations | |
// | |
func BenchmarkOneAppend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
write(&buf, append(a, "these", "are")...) | |
if buf.String() != "a few of my favorite things these are" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneVariadic(b *testing.B) { | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
write(&buf, "these", "are", "a", "few", "of", "my", "favorite", "things") | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOnePrepend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
write(&buf, prepend(a, "these", "are")...) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOnePrependInPlace(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
write(&buf, prependInPlaceCopy(a, "these", "are")...) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneSG(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
writeSG(&buf, []string{"these", "are"}, a) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
func BenchmarkOneIntf(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
writeIntf(&buf, "these", "are", a) | |
if buf.String() != "these are a few of my favorite things" { | |
b.Fatalf("bad result: %q", buf.String()) | |
} | |
} | |
} | |
// | |
// Various ideas for models, artificial usage | |
// | |
// Doesn't satisfy requirements, but sets the perf bar. | |
func BenchmarkAppend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
for j := 0; j < 16; j++ { | |
a = append(a, "these", "are") | |
} | |
write(&buf, a...) | |
//if buf.String() != "a few of my favorite things these are" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
func BenchmarkPrepend(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
for j := 0; j < 16; j++ { | |
a = prepend(a, "these", "are") | |
} | |
write(&buf, a...) | |
//if buf.String() != "these are a few of my favorite things" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
func BenchmarkPrependInPlaceManual(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
for j := 0; j < 16; j++ { | |
a = prependInPlace(a, "these", "are") | |
} | |
write(&buf, a...) | |
//if buf.String() != "these are a few of my favorite things" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
func BenchmarkPrependInPlaceCopy(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "a", "few", "of", "my", "favorite", "things") | |
for j := 0; j < 16; j++ { | |
a = prependInPlaceCopy(a, "these", "are") | |
} | |
write(&buf, a...) | |
//if buf.String() != "these are a few of my favorite things" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
func BenchmarkScatterGatherFlat(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], []string{"a", "few", "of", "my", "favorite", "things"}) | |
for j := 0; j < 16; j++ { | |
a = prependSG(a, "these", "are") | |
} | |
writeSG(&buf, a...) | |
//if buf.String() != "these are a few of my favorite things" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
type Phrase struct { | |
before []string | |
after *Phrase | |
} | |
func BenchmarkScatterGatherDeep(b *testing.B) { | |
buf := bytes.Buffer{} | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a := Phrase{before: []string{"a", "few", "of", "my", "favorite", "things"}} | |
for j := 0; j < 16; j++ { | |
a = prependSGDeep(a, "these", "are") | |
} | |
writeSGDeep(&buf, a) | |
//if buf.String() != "these are a few of my favorite things" { | |
//b.Fatalf("bad result: %q", buf.String()) | |
//} | |
} | |
} | |
// | |
// More representative patterns | |
// | |
func BenchmarkReprSGAsFewAsPossible(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeSG(&buf, []string{"-A", "CHAIN"}, a) | |
} | |
} | |
func BenchmarkReprSGMany(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
// Can't do writeSG(&buf, []string{"-A", "CHAIN"}, a...) -- go won't let us | |
writeSG(&buf, append([][]string{{"-A", "CHAIN"}}, a...)...) | |
} | |
} | |
func BenchmarkReprSGManyInline(b *testing.B) { | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeSG(&buf, | |
[]string{"-A", "CHAIN"}, | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}) | |
} | |
} | |
func BenchmarkReprIntfAsFewAsPossible(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeIntf(&buf, "-A", "CHAIN", a) | |
} | |
} | |
func BenchmarkReprIntfMany(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], []string{"-m", protocol, "-p", protocol}) | |
a = append(a, []string{"-d", ip, "--dport", port}) | |
a = append(a, []string{"-j", "FOOBAR"}) | |
// Can't do writeIntf(&buf, "-A", "CHAIN", a...) | |
// Can't do writeIntf(&buf, append([][]string{{"-A", "CHAIN"}}, a...)...) | |
s := []interface{}{"-A", "CHAIN"} | |
for _, x := range a { | |
s = append(s, x) | |
} | |
writeIntf(&buf, s...) | |
} | |
} | |
func BenchmarkReprIntfManyInline(b *testing.B) { | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeIntf(&buf, | |
"-A", "CHAIN", | |
[]string{"-m", protocol, "-p", protocol}, | |
[]string{"-d", ip, "--dport", port}, | |
[]string{"-j", "FOOBAR"}) | |
} | |
} | |
func BenchmarkReprClauseAsFewAsPossible(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeClause(&buf, appendClause("CHAIN"), argsClause(a)) | |
} | |
} | |
func BenchmarkReprClauseMany(b *testing.B) { | |
a := make([]clause, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], protocolClause(protocol)) | |
a = append(a, destClause(ip, port)) | |
a = append(a, jumpClause("FOOBAR")) | |
// Can't do writeClause(&buf, appendClause("CHAIN"), a...) | |
writeClause(&buf, appendClause("CHAIN"), metaClause(a...)) | |
} | |
} | |
func BenchmarkReprClauseManyInline(b *testing.B) { | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeClause(&buf, | |
appendClause("CHAIN"), | |
protocolClause(protocol), | |
destClause(ip, port), | |
jumpClause("FOOBAR")) | |
} | |
} | |
type clause func(buf *bytes.Buffer) | |
func appendClause(chain string) clause { | |
return func(buf *bytes.Buffer) { | |
write(buf, "-A", chain) | |
} | |
} | |
func protocolClause(proto string) clause { | |
return func(buf *bytes.Buffer) { | |
write(buf, "-m", proto, "-p", proto) | |
} | |
} | |
func destClause(ip, port string) clause { | |
return func(buf *bytes.Buffer) { | |
write(buf, "-d", ip, "--dport", port) | |
} | |
} | |
func jumpClause(chain string) clause { | |
return func(buf *bytes.Buffer) { | |
write(buf, "-j", chain) | |
} | |
} | |
func argsClause(args []string) clause { | |
return func(buf *bytes.Buffer) { | |
write(buf, args...) | |
} | |
} | |
func metaClause(clauses ...clause) clause { | |
return func(buf *bytes.Buffer) { | |
for _, c := range clauses { | |
c(buf) | |
} | |
} | |
} | |
func BenchmarkReprFuncAsFewAsPossible(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], "-m", protocol, "-p", protocol) | |
a = append(a, "-d", ip, "--dport", port) | |
a = append(a, "-j", "FOOBAR") | |
writeFunc(&buf, appendFunc("CHAIN"), a) | |
} | |
} | |
func BenchmarkReprFuncAsFewAsPossible2(b *testing.B) { | |
a := make([]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], protocolFunc(protocol)...) | |
a = append(a, destFunc(ip, port)...) | |
a = append(a, jumpFunc("FOOBAR")...) | |
writeFunc(&buf, appendFunc("CHAIN"), a) | |
} | |
} | |
func BenchmarkReprFuncMany(b *testing.B) { | |
a := make([][]string, 0, 64) | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
a = append(a[:0], protocolFunc(protocol)) | |
a = append(a, destFunc(ip, port)) | |
a = append(a, jumpFunc("FOOBAR")) | |
writeFunc(&buf, appendFunc("CHAIN"), a) | |
} | |
} | |
func BenchmarkReprFuncManyInline(b *testing.B) { | |
buf := bytes.Buffer{} | |
protocol := "tcp" | |
port := "1234" | |
ip := "1.2.3.4" | |
for i := 0; i < b.N; i++ { | |
buf.Reset() | |
writeFunc(&buf, | |
appendFunc("CHAIN"), | |
protocolFunc(protocol), | |
destFunc(ip, port), | |
jumpFunc("FOOBAR")) | |
} | |
} | |
func appendFunc(chain string) []string { | |
return []string{"-A", chain} | |
} | |
func protocolFunc(proto string) []string { | |
return []string{"-m", proto, "-p", proto} | |
} | |
func destFunc(ip, port string) []string { | |
return []string{"-d", ip, "--dport", port} | |
} | |
func jumpFunc(chain string) []string { | |
return []string{"-j", chain} | |
} | |
// other code used in the above | |
func prepend(sl []string, args ...string) []string { | |
return append(args, sl...) | |
} | |
func prependInPlace(sl []string, args ...string) []string { | |
toShift := len(sl) | |
toInsert := len(args) | |
sl = append(sl, args...) | |
for i := toShift - 1; i >= 0; i-- { | |
sl[i+toInsert] = sl[i] | |
} | |
for i, w := range args { | |
sl[i] = w | |
} | |
return sl | |
} | |
func prependInPlaceCopy(sl []string, args ...string) []string { | |
toInsert := len(args) | |
sl = append(sl, args...) | |
copy(sl[toInsert:], sl) | |
copy(sl[:toInsert], args) | |
return sl | |
} | |
func prependSG(sl [][]string, args ...string) [][]string { | |
sl = append(sl, args) | |
copy(sl[1:], sl) | |
sl[0] = args | |
return sl | |
} | |
func prependSGDeep(p Phrase, args ...string) Phrase { | |
return Phrase{ | |
before: args, | |
after: &p, | |
} | |
} | |
// go:noinline | |
func write(buf *bytes.Buffer, words ...string) { | |
for i, w := range words { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
buf.WriteString(w) | |
} | |
} | |
// go:noinline | |
func writeSG(buf *bytes.Buffer, phrases ...[]string) { | |
for i, p := range phrases { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
write(buf, p...) | |
} | |
} | |
// go:noinline | |
func writeSGDeep(buf *bytes.Buffer, p Phrase) { | |
write(buf, p.before...) | |
if p.after != nil { | |
buf.WriteByte(' ') | |
writeSGDeep(buf, *p.after) | |
} | |
} | |
// go:noinline | |
func writeIntf(buf *bytes.Buffer, parts ...interface{}) { | |
for i, p := range parts { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
switch x := p.(type) { | |
case string: | |
buf.WriteString(x) | |
case []string: | |
write(buf, x...) | |
default: | |
panic("huh?") | |
} | |
} | |
} | |
// go:noinline | |
func writeClause(buf *bytes.Buffer, clauses ...clause) { | |
for i, c := range clauses { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
c(buf) | |
} | |
} | |
// go:noinline | |
func writeFunc(buf *bytes.Buffer, parts ...interface{}) { | |
for i, p := range parts { | |
if i > 0 { | |
buf.WriteByte(' ') | |
} | |
switch x := p.(type) { | |
case string: | |
buf.WriteString(x) | |
case []string: | |
write(buf, x...) | |
case [][]string: | |
writeSG(buf, x...) | |
default: | |
panic("huh?") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment