├── .gitignore ├── Makefile ├── README.md ├── append_bytes_test.go ├── argwriter.go ├── argwriter_results.md ├── argwriter_test.go ├── atomic_test.go ├── atomicwg_test.go ├── bit_test.go ├── caller_test.go ├── connecion_test.go ├── context_test.go ├── dial_test.go ├── formatint_test.go ├── glob_test.go ├── go.mod ├── go.sum ├── goroutine_test.go ├── hex_bench_test.go ├── hostport_test.go ├── http_test.go ├── iface_allocs_test.go ├── indirect_test.go ├── interface_conv_test.go ├── map-lookup-size └── map_lookup_size_test.go ├── map_contains_test.go ├── map_int ├── map_int_test.go └── results-1.10 ├── map_set_test.go ├── map_vs_slice_test.go ├── maplookup.go ├── maplookup_results.md ├── maplookup_test.go ├── mod_test.go ├── mutex.go ├── mutex_results.md ├── mutex_test.go ├── new_bench_test.go ├── rand_bench_test.go ├── ratelimit ├── interface.go ├── locked_counter.go ├── ratelimit_test.go └── time_period.go ├── receiver.go ├── receiver_results.md ├── receiver_test.go ├── scripts └── markdown.sh ├── sort ├── bench.out ├── go.mod ├── prof.mem └── sorted_list_test.go ├── sorted_vs_heap ├── bench.out ├── go.mod ├── go.sum └── sorted_vs_heap_test.go ├── string_append_test.go ├── string_cast_bench_test.go ├── string_compare_test.go ├── syscalls_test.go ├── uuid_arg_test.go └── wgchan_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | *.prof 3 | 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOTESTFILES := $(wildcard *_test.go) 2 | RESULTS = $(GOTESTFILES:_test.go=_results.md) 3 | 4 | MARKDOWN=scripts/markdown.sh 5 | 6 | %_test: %.go %_test.go 7 | go test -bench . $^ 8 | 9 | %_results.md: %.go %_test.go $(MARKDOWN) 10 | go test -bench . $(filter %.go,$^) | $(MARKDOWN) $* > $@ 11 | 12 | results: $(RESULTS) 13 | 14 | clean: 15 | rm -rf *_results.md 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Benchmarks 2 | 3 | * [Mutex](mutex_results.md) 4 | * [Map Lookup](maplookup_results.md) 5 | * [Receiver](receiver_results.md) 6 | * [Arg Writer](argwriter_results.md) 7 | -------------------------------------------------------------------------------- /append_bytes_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkAppendString(b *testing.B) { 6 | bs := make([]byte, 100) 7 | for i := 0; i < b.N; i++ { 8 | bs = bs[:0] 9 | bs = append(bs, "\n}"...) 10 | } 11 | } 12 | 13 | func BenchmarkAppendBytes(b *testing.B) { 14 | bs := make([]byte, 100) 15 | for i := 0; i < b.N; i++ { 16 | bs = bs[:0] 17 | bs = append(bs, '\\', '\n') 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /argwriter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "io" 4 | 5 | type argWriter struct { 6 | writer io.WriteCloser 7 | err error 8 | } 9 | 10 | func newArgWriterPtr(writer io.WriteCloser, err error) *argWriter { 11 | return &argWriter{writer, err} 12 | } 13 | 14 | func newArgWriterVal(writer io.WriteCloser, err error) argWriter { 15 | return argWriter{writer, err} 16 | } 17 | 18 | func (w argWriter) writeVal(f func() error) error { 19 | if w.err != nil { 20 | return w.err 21 | } 22 | 23 | if err := f(); err != nil { 24 | return err 25 | } 26 | 27 | return w.writer.Close() 28 | } 29 | 30 | func (w argWriter) writePtr(f func() error) error { 31 | if w.err != nil { 32 | return w.err 33 | } 34 | 35 | if err := f(); err != nil { 36 | return err 37 | } 38 | 39 | return w.writer.Close() 40 | } 41 | 42 | func (w argWriter) WriteIndirectVal(bs []byte) error { 43 | return w.writeVal(func() error { 44 | _, err := w.writer.Write(bs) 45 | return err 46 | }) 47 | } 48 | 49 | func (w *argWriter) WriteIndirectPtr(bs []byte) error { 50 | return w.writePtr(func() error { 51 | _, err := w.writer.Write(bs) 52 | return err 53 | }) 54 | } 55 | 56 | func (w argWriter) WriteDirectVal(bs []byte) error { 57 | if w.err != nil { 58 | return w.err 59 | } 60 | 61 | if _, err := w.writer.Write(bs); err != nil { 62 | return err 63 | } 64 | 65 | return w.writer.Close() 66 | } 67 | 68 | func (w *argWriter) WriteDirectPtr(bs []byte) error { 69 | if w.err != nil { 70 | return w.err 71 | } 72 | 73 | if _, err := w.writer.Write(bs); err != nil { 74 | return err 75 | } 76 | 77 | return w.writer.Close() 78 | } 79 | -------------------------------------------------------------------------------- /argwriter_results.md: -------------------------------------------------------------------------------- 1 | ## Argwriter Results 2 | 3 | Benchmark Name|Iterations|Per-Iteration 4 | ----|----|---- 5 | BenchmarkWriteIndirectVal_Val|20000000| 109 ns/op 6 | BenchmarkWriteIndirectVal_Ptr|10000000| 133 ns/op 7 | BenchmarkWriteIndirectPtr|10000000| 194 ns/op 8 | BenchmarkWriteDirectVal_Val|20000000| 110 ns/op 9 | BenchmarkWriteDirectVal_Ptr|20000000| 112 ns/op 10 | BenchmarkWriteDirectPtr|10000000| 186 ns/op 11 | BenchmarkNoWriter|20000000| 127 ns/op 12 | 13 | Generated using go version go1.4.2 darwin/amd64 14 | -------------------------------------------------------------------------------- /argwriter_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "io" 7 | "testing" 8 | ) 9 | 10 | // The different versions: 11 | // Indirect = uses the writePr func with a closure 12 | // Direct = doesn't use the writePtr func 13 | // Val suffix = uses a value receiver 14 | // Ptr suffix = uses a pointer receiver 15 | // Val_Val: Creates a Val, and uses the Val method 16 | // Val_Ptr: Creates a Val, but uses the Ptr method. 17 | 18 | var ( 19 | dataToWrite []byte 20 | numBytes = flag.Int("numBytes", 50, "Number of bytes to write") 21 | ) 22 | 23 | func init() { 24 | flag.Parse() 25 | 26 | const source = "hello world" 27 | lenSource := len(source) 28 | for i := 0; i < *numBytes; i++ { 29 | dataToWrite = append(dataToWrite, source[i%lenSource]) 30 | } 31 | } 32 | 33 | type addClose struct { 34 | io.Writer 35 | } 36 | 37 | func (addClose) Close() error { 38 | return nil 39 | } 40 | 41 | func writerCloser(writer io.Writer) io.WriteCloser { 42 | return addClose{writer} 43 | } 44 | 45 | func Writer(writer io.Writer) (io.WriteCloser, error) { 46 | return writerCloser(writer), nil 47 | } 48 | 49 | func BenchmarkWriteIndirectVal_Val(b *testing.B) { 50 | var buf bytes.Buffer 51 | for i := 0; i < b.N; i++ { 52 | newArgWriterVal(Writer(&buf)).WriteIndirectVal(dataToWrite) 53 | buf.Reset() 54 | } 55 | } 56 | 57 | func BenchmarkWriteIndirectVal_Ptr(b *testing.B) { 58 | var buf bytes.Buffer 59 | for i := 0; i < b.N; i++ { 60 | newArgWriterPtr(Writer(&buf)).WriteIndirectVal(dataToWrite) 61 | buf.Reset() 62 | } 63 | } 64 | 65 | func BenchmarkWriteIndirectPtr(b *testing.B) { 66 | var buf bytes.Buffer 67 | for i := 0; i < b.N; i++ { 68 | newArgWriterPtr(Writer(&buf)).WriteIndirectPtr(dataToWrite) 69 | buf.Reset() 70 | } 71 | } 72 | 73 | func BenchmarkWriteDirectVal_Val(b *testing.B) { 74 | var buf bytes.Buffer 75 | for i := 0; i < b.N; i++ { 76 | newArgWriterVal(Writer(&buf)).WriteDirectVal(dataToWrite) 77 | buf.Reset() 78 | } 79 | } 80 | 81 | func BenchmarkWriteDirectVal_Ptr(b *testing.B) { 82 | var buf bytes.Buffer 83 | for i := 0; i < b.N; i++ { 84 | newArgWriterPtr(Writer(&buf)).WriteDirectVal(dataToWrite) 85 | buf.Reset() 86 | } 87 | } 88 | 89 | func BenchmarkWriteDirectPtr(b *testing.B) { 90 | var buf bytes.Buffer 91 | for i := 0; i < b.N; i++ { 92 | newArgWriterPtr(Writer(&buf)).WriteDirectPtr(dataToWrite) 93 | buf.Reset() 94 | } 95 | } 96 | 97 | func BenchmarkNoWriter(b *testing.B) { 98 | var buf bytes.Buffer 99 | for i := 0; i < b.N; i++ { 100 | writer, err := Writer(&buf) 101 | if err == nil { 102 | _, err = writer.Write(dataToWrite) 103 | if err == nil { 104 | err = writer.Close() 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /atomic_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkAtomicInc(b *testing.B) { 10 | var v int32 11 | b.RunParallel(func(pb *testing.PB) { 12 | for pb.Next() { 13 | atomic.AddInt32(&v, 1) 14 | } 15 | }) 16 | } 17 | 18 | func checkZero(v int32) { 19 | if v != 0 { 20 | panic("number should be 0") 21 | } 22 | } 23 | 24 | func BenchmarkAtomicRead(b *testing.B) { 25 | var v int32 26 | b.RunParallel(func(pb *testing.PB) { 27 | for pb.Next() { 28 | checkZero(atomic.LoadInt32(&v)) 29 | } 30 | }) 31 | } 32 | 33 | func BenchmarkNonAtomicRead(b *testing.B) { 34 | var v int32 35 | b.RunParallel(func(pb *testing.PB) { 36 | for pb.Next() { 37 | checkZero(v) 38 | } 39 | }) 40 | } 41 | 42 | func benchmarkReadWrite(b *testing.B, readPercent int, readFn func() int32, writeFn func(v int32)) { 43 | b.RunParallel(func(pb *testing.PB) { 44 | i := 0 45 | for pb.Next() { 46 | if i == 100 { 47 | i = 0 48 | } 49 | if i < readPercent { 50 | readFn() 51 | } else { 52 | writeFn(1) 53 | } 54 | } 55 | }) 56 | } 57 | 58 | func BenchmarkReadWriteAtomicRead90(b *testing.B) { 59 | var v int32 60 | benchmarkReadWrite(b, 90, func() int32 { 61 | return atomic.LoadInt32(&v) 62 | }, func(newV int32) { 63 | atomic.StoreInt32(&v, newV) 64 | }) 65 | } 66 | 67 | func BenchmarkReadWriteLockRead90(b *testing.B) { 68 | var mu sync.Mutex 69 | var v int32 70 | benchmarkReadWrite(b, 90, func() int32 { 71 | mu.Lock() 72 | v := v 73 | mu.Unlock() 74 | return v 75 | }, func(newV int32) { 76 | mu.Lock() 77 | v = newV 78 | mu.Unlock() 79 | }) 80 | } 81 | 82 | func BenchmarkAtomicCompareCAS(b *testing.B) { 83 | var atom int32 84 | b.RunParallel(func(pb *testing.PB) { 85 | for pb.Next() { 86 | atomic.CompareAndSwapInt32(&atom, 1, 2) 87 | } 88 | }) 89 | } 90 | 91 | func BenchmarkAtomicCompareReadWrite(b *testing.B) { 92 | var atom int32 93 | b.RunParallel(func(pb *testing.PB) { 94 | for pb.Next() { 95 | if atomic.LoadInt32(&atom) == 1 { 96 | atomic.CompareAndSwapInt32(&atom, 1, 2) 97 | } 98 | } 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /atomicwg_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkWG(b *testing.B) { 10 | var wg sync.WaitGroup 11 | b.RunParallel(func(pb *testing.PB) { 12 | for pb.Next() { 13 | wg.Add(1) 14 | wg.Done() 15 | } 16 | }) 17 | } 18 | 19 | func BenchmarkAtomic(b *testing.B) { 20 | var n int32 21 | b.RunParallel(func(pb *testing.PB) { 22 | for pb.Next() { 23 | atomic.AddInt32(&n, 1) 24 | atomic.AddInt32(&n, -1) 25 | } 26 | }) 27 | if n != 0 { 28 | panic("fail") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /bit_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | // Package level variables to ensure compiler doesn't optimize away benchmark 6 | var ( 7 | _ignored1 bool 8 | _ignored2 bool 9 | _ignored3 bool 10 | _ignored4 bool 11 | ) 12 | 13 | const ( 14 | check1 = 1 << iota 15 | check2 16 | check3 17 | check4 18 | ) 19 | 20 | func BenchmarkBitCheckInt(b *testing.B) { 21 | for i := 0; i < b.N; i++ { 22 | v := int(i) 23 | _ignored1 = (v & check1) != 0 24 | _ignored2 = (v & check2) != 0 25 | _ignored3 = (v & check3) != 0 26 | _ignored4 = (v & check4) != 0 27 | } 28 | } 29 | 30 | func BenchmarkBitCheckUint8(b *testing.B) { 31 | for i := 0; i < b.N; i++ { 32 | v := uint8(i) 33 | _ignored1 = (v & check1) != 0 34 | _ignored2 = (v & check2) != 0 35 | _ignored3 = (v & check3) != 0 36 | _ignored4 = (v & check4) != 0 37 | } 38 | } 39 | 40 | func BenchmarkBitCheckUint16(b *testing.B) { 41 | for i := 0; i < b.N; i++ { 42 | v := uint16(i) 43 | _ignored1 = (v & check1) != 0 44 | _ignored2 = (v & check2) != 0 45 | _ignored3 = (v & check3) != 0 46 | _ignored4 = (v & check4) != 0 47 | } 48 | } 49 | 50 | func BenchmarkBitCheckUint32(b *testing.B) { 51 | for i := 0; i < b.N; i++ { 52 | v := uint32(i) 53 | _ignored1 = (v & check1) != 0 54 | _ignored2 = (v & check2) != 0 55 | _ignored3 = (v & check3) != 0 56 | _ignored4 = (v & check4) != 0 57 | } 58 | } 59 | 60 | func BenchmarkBitCheckUint64(b *testing.B) { 61 | for i := 0; i < b.N; i++ { 62 | v := uint64(i) 63 | _ignored1 = (v & check1) != 0 64 | _ignored2 = (v & check2) != 0 65 | _ignored3 = (v & check3) != 0 66 | _ignored4 = (v & check4) != 0 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /caller_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | ) 8 | 9 | func f5() string { 10 | pc, _, _, _ := runtime.Caller(1) 11 | return runtime.FuncForPC(pc).Name() 12 | } 13 | 14 | func f4() string { 15 | return f5() 16 | } 17 | 18 | func f3() string { 19 | return f4() 20 | } 21 | 22 | func f2() string { 23 | return f3() 24 | } 25 | 26 | func f1() string { 27 | return f2() 28 | } 29 | 30 | func BenchmarkCaller(b *testing.B) { 31 | var s string 32 | for i := 0; i < b.N; i++ { 33 | s = f1() 34 | } 35 | fmt.Println("s", s) 36 | } 37 | -------------------------------------------------------------------------------- /connecion_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "testing" 7 | ) 8 | 9 | const packetSize = 16 10 | 11 | func connectToServer(t testing.TB) net.Conn { 12 | ln, err := net.Listen("tcp", "127.0.0.1:0") 13 | if err != nil { 14 | t.Fatalf("Failed to listen: %v", err) 15 | } 16 | 17 | go acceptLoop(t, ln) 18 | 19 | conn, err := net.Dial("tcp", ln.Addr().String()) 20 | if err != nil { 21 | t.Fatalf("net.Dial failed: %v", err) 22 | } 23 | 24 | return conn 25 | } 26 | 27 | func acceptLoop(t testing.TB, ln net.Listener) { 28 | defer ln.Close() 29 | conn, err := ln.Accept() 30 | if err != nil { 31 | t.Fatalf("Accept failed: %v", err) 32 | } 33 | 34 | data := make([]byte, packetSize) 35 | for { 36 | if readBytes(t, conn, data) { 37 | return 38 | } 39 | if readBytes(t, conn, data) { 40 | return 41 | } 42 | writeBytes(t, conn, data) 43 | writeBytes(t, conn, data) 44 | } 45 | } 46 | 47 | func readBytes(t testing.TB, r io.Reader, data []byte) bool { 48 | if _, err := io.ReadFull(r, data); err != nil { 49 | if err == io.EOF { 50 | return true 51 | } 52 | 53 | t.Fatalf("Failed to read data: %v", err) 54 | } 55 | return false 56 | } 57 | 58 | func writeBytes(t testing.TB, w io.Writer, data []byte) { 59 | if _, err := w.Write(data); err != nil { 60 | t.Fatalf("Failed to write data: %v", err) 61 | } 62 | } 63 | 64 | // BenchmarkConnectionRoundtrip measures the latency for sending a packet and getting a response. 65 | // The caller writes 2 packets with packetSize, the receiver reads these packets and immediately 66 | // sends them back. There is no work performed on the reciever. 67 | // There is no memory allocated during the send/receive. 68 | func BenchmarkConnectionRoundtripSerial(b *testing.B) { 69 | conn := connectToServer(b) 70 | defer conn.Close() 71 | 72 | bs := make([]byte, packetSize) 73 | bs[0] = 1 74 | bs[packetSize-1] = 2 75 | 76 | b.ResetTimer() 77 | for i := 0; i < b.N; i++ { 78 | writeBytes(b, conn, bs) 79 | writeBytes(b, conn, bs) 80 | readBytes(b, conn, bs) 81 | readBytes(b, conn, bs) 82 | } 83 | } 84 | 85 | func benchmarkConnectionRoundtripParallel(b *testing.B, parallelism int) { 86 | b.SetParallelism(parallelism) 87 | b.RunParallel(func(pb *testing.PB) { 88 | conn := connectToServer(b) 89 | defer conn.Close() 90 | 91 | bs := make([]byte, packetSize) 92 | bs[0] = 1 93 | bs[packetSize-1] = 2 94 | 95 | for pb.Next() { 96 | writeBytes(b, conn, bs) 97 | writeBytes(b, conn, bs) 98 | readBytes(b, conn, bs) 99 | readBytes(b, conn, bs) 100 | } 101 | }) 102 | } 103 | 104 | func BenchmarkConnectionRoundtripParallel1(b *testing.B) { 105 | benchmarkConnectionRoundtripParallel(b, 1) 106 | } 107 | 108 | func BenchmarkConnectionRoundtripParallel2(b *testing.B) { 109 | benchmarkConnectionRoundtripParallel(b, 2) 110 | } 111 | 112 | func BenchmarkConnectionRoundtripParallel4(b *testing.B) { 113 | benchmarkConnectionRoundtripParallel(b, 4) 114 | } 115 | 116 | func BenchmarkConnectionRoundtripParallel8(b *testing.B) { 117 | benchmarkConnectionRoundtripParallel(b, 8) 118 | } 119 | -------------------------------------------------------------------------------- /context_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "golang.org/x/net/context" 8 | ) 9 | 10 | var ctx context.Context 11 | 12 | func BenchmarkContextWithDeadline(b *testing.B) { 13 | for i := 0; i < b.N; i++ { 14 | newCtx, cancel := context.WithTimeout(context.Background(), time.Second) 15 | ctx = newCtx 16 | cancel() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dial_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | type addr struct { 10 | hp string 11 | raddr *net.TCPAddr 12 | } 13 | 14 | func BenchmarkDial(b *testing.B) { 15 | tests := []struct { 16 | name string 17 | dialFn func(a addr) (net.Conn, error) 18 | }{ 19 | { 20 | name: "net.Dial", 21 | dialFn: func(a addr) (net.Conn, error) { 22 | return net.Dial("tcp", a.hp) 23 | }, 24 | }, 25 | { 26 | name: "net.DialTCP", 27 | dialFn: func(a addr) (net.Conn, error) { 28 | return net.DialTCP("tcp", nil, a.raddr) 29 | }, 30 | }, 31 | { 32 | name: "net.DialTimeout", 33 | dialFn: func(a addr) (net.Conn, error) { 34 | return net.DialTimeout("tcp", a.hp, time.Second) 35 | }, 36 | }, 37 | } 38 | 39 | for _, tt := range tests { 40 | b.Run(tt.name, func(b *testing.B) { 41 | ln, err := net.Listen("tcp", "127.0.0.1:0") 42 | if err != nil { 43 | panic(err) 44 | } 45 | 46 | go func() { 47 | for { 48 | c, err := ln.Accept() 49 | if err != nil { 50 | return 51 | } 52 | 53 | c.Close() 54 | } 55 | }() 56 | 57 | hp := ln.Addr().String() 58 | raddr, err := net.ResolveTCPAddr("tcp", hp) 59 | if err != nil { 60 | panic(err) 61 | } 62 | 63 | a := addr{hp, raddr} 64 | for i := 0; i < b.N; i++ { 65 | c, err := tt.dialFn(a) 66 | if err != nil { 67 | b.Errorf("Dial failed: %v", err) 68 | } else { 69 | c.Close() 70 | } 71 | } 72 | }) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /formatint_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | var res string 10 | 11 | func BenchmarkFormatInt(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | res = strconv.FormatInt(int64(i), 10) 14 | } 15 | } 16 | 17 | func BenchmarkSprint(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | res = fmt.Sprint(i) 20 | } 21 | } 22 | 23 | func BenchmarkItoa(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | res = strconv.Itoa(i) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /glob_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "path/filepath" 5 | "testing" 6 | 7 | gglob "github.com/gobwas/glob" 8 | goglob "github.com/ryanuber/go-glob" 9 | v23glob "v.io/v23/glob" 10 | ) 11 | 12 | type matcher func(s string) bool 13 | 14 | func BenchmarkGlob(b *testing.B) { 15 | glob := "**.bad-request" 16 | match := []string{".bad-request", "svc.bad-request", "caller.dest.bad-request", "this.is.a.really.long.long.thing.that.will.end.up.matching.the.bad-request"} 17 | noMatch := []string{"", "bad-request", ".bad-request.", "random", "this.is.a.really.long.long.thing.that.will.not.end.up.matching.the.bad.request"} 18 | 19 | v23g, err := v23glob.Parse(glob) 20 | if err != nil { 21 | panic(err) 22 | } 23 | 24 | gg, err := gglob.Compile(glob, '.') 25 | if err != nil { 26 | panic(err) 27 | } 28 | 29 | runs := []struct { 30 | name string 31 | m matcher 32 | }{ 33 | { 34 | name: "go-glob", 35 | m: func(s string) bool { 36 | return goglob.Glob(glob, s) 37 | }, 38 | }, 39 | { 40 | name: "v23glob", 41 | m: func(s string) bool { 42 | return v23g.Head().Match(s) 43 | }, 44 | }, 45 | { 46 | name: "gobwas/glob", 47 | m: func(s string) bool { 48 | return gg.Match(s) 49 | }, 50 | }, 51 | { 52 | name: "filepath/match", 53 | m: func(s string) bool { 54 | ok, _ := filepath.Match(glob, s) 55 | return ok 56 | }, 57 | }, 58 | } 59 | 60 | for _, r := range runs { 61 | b.Run(r.name, func(b *testing.B) { 62 | for i := 0; i < b.N; i++ { 63 | for _, m := range match { 64 | if !r.m(m) { 65 | panic("fail") 66 | } 67 | } 68 | for _, m := range noMatch { 69 | if r.m(m) { 70 | panic("fail") 71 | } 72 | } 73 | } 74 | }) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prashantv/go-bench 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gobwas/glob v0.2.3 7 | github.com/ryanuber/go-glob v1.0.0 8 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd 9 | v.io v0.1.20 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 6 | github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 7 | github.com/aws/aws-sdk-go v1.17.12/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 8 | github.com/aws/aws-sdk-go v1.38.24/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= 9 | github.com/aws/aws-xray-sdk-go v1.3.0/go.mod h1:tmxq1c+yeEbMh39OmRFuXOrse5ajRlMmDXJ6LrCVsIs= 10 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 11 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 12 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 13 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 14 | github.com/davecgh/go-spew v0.0.0-20160907170601-6d212800a42e/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 17 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 18 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 19 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 20 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 21 | github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 22 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 23 | github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= 24 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 25 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 26 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 27 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 28 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 29 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 30 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 31 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 32 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 33 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 34 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 35 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 36 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 37 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 38 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 39 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 40 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 41 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 42 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 43 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 44 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 45 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 46 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 47 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 48 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 49 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 50 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 51 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 52 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 53 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 54 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 55 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 56 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 57 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 58 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 59 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 60 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 61 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 62 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 63 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 64 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 65 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 66 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 67 | github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= 68 | github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= 69 | github.com/shirou/gopsutil v2.19.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= 70 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 71 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 72 | github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 73 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 74 | github.com/vanadium/go-mdns-sd v0.0.0-20181006014439-f1a1ccd1252e/go.mod h1:35fXDjvKtzyf89fHHhyTTNLHaG2CkI7u/GvO59PIjP4= 75 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 76 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 77 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 78 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 79 | golang.org/x/crypto v0.0.0-20210513122933-cd7d49e622d5/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 80 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 81 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 82 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 83 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 84 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 85 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 86 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 87 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 88 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 89 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 90 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 91 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 92 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 93 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 94 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 95 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 96 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 97 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 98 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 99 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= 100 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 101 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 102 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 103 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 104 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 105 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 106 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 107 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 108 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 109 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 110 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 111 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 112 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 113 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 114 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 115 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 116 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 117 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 118 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 119 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 120 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 121 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 122 | golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= 123 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 124 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 125 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 126 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 127 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 128 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 129 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 130 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 131 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 132 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 133 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 134 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 135 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 136 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 137 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 138 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 139 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 140 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 141 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 142 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 143 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 144 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 145 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 146 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 147 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 148 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 149 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 150 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 151 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 152 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 153 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 154 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 155 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 156 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 157 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 158 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 159 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 160 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 161 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 162 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 163 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 164 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 165 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 166 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 167 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 168 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 169 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 170 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 171 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 172 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 173 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 174 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 175 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 176 | v.io v0.1.20 h1:0rx3NVvMOvNYV6Q6GBbXPUOiPIIx76UYXfgLdQKzHRc= 177 | v.io v0.1.20/go.mod h1:iVzQ9O0wfm38tP74JfSejmDPtCoZVtAhKpoe4YMzdEI= 178 | v.io/x/lib v0.1.6/go.mod h1:aLm+mPXyXf4Vd/n+1f4LcSQFFgqNhNzwQvHYfXoOLlE= 179 | v.io/x/lib v0.1.7/go.mod h1:aLm+mPXyXf4Vd/n+1f4LcSQFFgqNhNzwQvHYfXoOLlE= 180 | v.io/x/ref/internal/logger v0.1.1/go.mod h1:00nuJdZEVCzMOn9y474jZ+e6B9R/ydLW7d6IQFl/NHU= 181 | v.io/x/ref/lib/flags/sitedefaults v0.1.1/go.mod h1:ew4Igo60KMBDYhnxH6l7P+qBCJiqR8PVp7fJJYGqILA= 182 | -------------------------------------------------------------------------------- /goroutine_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkGoroutineCost(b *testing.B) { 9 | var wg sync.WaitGroup 10 | 11 | wg.Add(b.N) 12 | for i := 0; i < b.N; i++ { 13 | go wg.Done() 14 | } 15 | wg.Wait() 16 | } 17 | 18 | func BenchmarkNoGoroutine(b *testing.B) { 19 | var wg sync.WaitGroup 20 | 21 | wg.Add(b.N) 22 | for i := 0; i < b.N; i++ { 23 | wg.Done() 24 | } 25 | wg.Wait() 26 | } 27 | -------------------------------------------------------------------------------- /hex_bench_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/hex" 6 | "fmt" 7 | "math" 8 | "strconv" 9 | "testing" 10 | ) 11 | 12 | func hexEncode(i uint64) string { 13 | b := make([]byte, 8) 14 | binary.BigEndian.PutUint64(b, i) 15 | return hex.EncodeToString(b) 16 | } 17 | 18 | func sprint(i uint64) string { 19 | return fmt.Sprintf("%016x", i) 20 | } 21 | 22 | const spaces = " " 23 | 24 | func strconvFormat(i uint64) string { 25 | s := strconv.FormatUint(i, 16) 26 | if len(s) < 16 { 27 | s = spaces[:16-len(s)] + s 28 | } 29 | return s 30 | } 31 | 32 | func BenchmarkHexEncode(b *testing.B) { 33 | tests := []struct { 34 | msg string 35 | f func(uint64) string 36 | }{ 37 | {"hexEncode", hexEncode}, 38 | {"sprintf", sprint}, 39 | {"strconv", strconvFormat}, 40 | } 41 | 42 | for _, tt := range tests { 43 | b.Run(tt.msg, func(b *testing.B) { 44 | for i := 0; i < b.N; i++ { 45 | _ = tt.f(uint64(i)) 46 | } 47 | }) 48 | } 49 | } 50 | 51 | func TestAll(t *testing.T) { 52 | for i := uint64(math.MaxUint64); i > 0; i-- { 53 | i := i 54 | if i%2 == 0 { 55 | i = math.MaxUint64 - i 56 | } 57 | a := hexEncode(i) 58 | b := sprint(i) 59 | c := strconvFormat(i) 60 | 61 | if a == b && b == c { 62 | continue 63 | } 64 | 65 | fmt.Println("mismatch for", i, a, b, c) 66 | return 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /hostport_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | // var testHostPort = "127.0.0.1:1234" 11 | var testHostPort = "127.127.127.127:1234" 12 | 13 | const printHost = false 14 | 15 | // getHostStd uses strings.IndexByte to find the location of the colon 16 | // and returns the string up to that point. 17 | func getHostIndexByte(hostPort string) string { 18 | if idx := strings.IndexByte(hostPort, ':'); idx > 0 { 19 | return hostPort[:idx] 20 | } 21 | return hostPort 22 | } 23 | 24 | func getHostSplitHostPort(hostPort string) string { 25 | if host, _, err := net.SplitHostPort(hostPort); err == nil { 26 | return host 27 | } 28 | return hostPort 29 | } 30 | 31 | // getHostIndexLoop uses a for loop to find the location of the colon and 32 | // returns the string up to that point. 33 | func getHostIndexLoop(hostPort string) string { 34 | for i := 0; i < len(hostPort); i++ { 35 | if hostPort[i] == ':' { 36 | return hostPort[:i] 37 | } 38 | } 39 | return hostPort 40 | } 41 | 42 | // getHostRangeLoop uses a for loop to find the location of the colon and 43 | // returns the string up to that point. 44 | func getHostRangeLoop(hostPort string) string { 45 | for i, c := range hostPort { 46 | if c == ':' { 47 | return hostPort[:i] 48 | } 49 | } 50 | return hostPort 51 | } 52 | 53 | func BenchmarkGetHostIndexByte(b *testing.B) { 54 | var host string 55 | for i := 0; i < b.N; i++ { 56 | host = getHostIndexByte(testHostPort) 57 | } 58 | if printHost { 59 | fmt.Println(host) 60 | } 61 | } 62 | 63 | func BenchmarkGetHostSplitHostPort(b *testing.B) { 64 | var host string 65 | for i := 0; i < b.N; i++ { 66 | host = getHostSplitHostPort(testHostPort) 67 | } 68 | if printHost { 69 | fmt.Println(host) 70 | } 71 | } 72 | 73 | func BenchmarkGetHostIndexLoop(b *testing.B) { 74 | var host string 75 | for i := 0; i < b.N; i++ { 76 | host = getHostIndexLoop(testHostPort) 77 | } 78 | if printHost { 79 | fmt.Println(host) 80 | } 81 | } 82 | 83 | func BenchmarkGetHostRangeLoop(b *testing.B) { 84 | var host string 85 | for i := 0; i < b.N; i++ { 86 | host = getHostRangeLoop(testHostPort) 87 | } 88 | if printHost { 89 | fmt.Println(host) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /http_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "net" 8 | "net/http" 9 | "testing" 10 | "time" 11 | 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | func setupServer(t testing.TB, handlerFunc func()) string { 16 | ln, err := net.Listen("tcp", "127.0.0.1:0") 17 | if err != nil { 18 | t.Fatalf("net.Listen failed: %v", err) 19 | } 20 | 21 | helloWorldBytes := []byte("Hello world") 22 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 23 | handlerFunc() 24 | w.Write(helloWorldBytes) 25 | 26 | }) 27 | go http.Serve(ln, handler) 28 | 29 | return fmt.Sprintf("http://%v/test", ln.Addr().String()) 30 | } 31 | 32 | func doGet(t testing.TB, client *http.Client, url string) { 33 | resp, err := client.Get(url) 34 | defer resp.Body.Close() 35 | if err != nil { 36 | t.Fatalf("Get failed: %v", err) 37 | } 38 | 39 | if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil { 40 | t.Fatalf("ReadAll failed: %v", err) 41 | } 42 | } 43 | 44 | func BenchmarkHTTPCall(b *testing.B) { 45 | client := &http.Client{} 46 | url := setupServer(b, func() {}) 47 | // Create a connection that will be reused. 48 | doGet(b, client, url) 49 | 50 | b.ResetTimer() 51 | for i := 0; i < b.N; i++ { 52 | doGet(b, client, url) 53 | } 54 | } 55 | 56 | func BenchmarkHTTPCallWithCtx(b *testing.B) { 57 | client := &http.Client{} 58 | url := setupServer(b, func() { 59 | _, cancel := context.WithTimeout(context.Background(), time.Second) 60 | cancel() 61 | }) 62 | // Create a connection that will be reused. 63 | doGet(b, client, url) 64 | 65 | b.ResetTimer() 66 | for i := 0; i < b.N; i++ { 67 | _, cancel := context.WithTimeout(context.Background(), time.Second) 68 | doGet(b, client, url) 69 | cancel() 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /iface_allocs_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | var _ifaceLast interface{} 6 | 7 | type emptyStruct struct{} 8 | 9 | type nonemptyStruct struct{ Name string } 10 | 11 | func BenchmarkEmptyStructInterface(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | _ifaceLast = emptyStruct{} 14 | } 15 | } 16 | 17 | func BenchmarkEmptyStructPtrInterface(b *testing.B) { 18 | s := &emptyStruct{} 19 | for i := 0; i < b.N; i++ { 20 | _ifaceLast = s 21 | } 22 | } 23 | 24 | func BenchmarkSmallStructInterface(b *testing.B) { 25 | for i := 0; i < b.N; i++ { 26 | _ifaceLast = nonemptyStruct{} 27 | } 28 | } 29 | 30 | func BenchmarkSmallStructPtrInterface(b *testing.B) { 31 | s := &nonemptyStruct{} 32 | for i := 0; i < b.N; i++ { 33 | _ifaceLast = s 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /indirect_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | var stringsCompare = strings.Compare 9 | 10 | func BenchmarkDirectMethodCall(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | strings.Compare("", "") 13 | } 14 | } 15 | 16 | func BenchmarkIndirectMethodCall(b *testing.B) { 17 | for i := 0; i < b.N; i++ { 18 | stringsCompare("", "") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /interface_conv_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | type Interface interface { 6 | Get() string 7 | } 8 | 9 | type Impl struct{} 10 | 11 | func (i *Impl) Get() string { return "test" } 12 | 13 | func getI(i Interface) { 14 | i.Get() 15 | } 16 | 17 | func BenchmarkInterfaceConvInLoop(b *testing.B) { 18 | v := &Impl{} 19 | for i := 0; i < b.N; i++ { 20 | getI(v) 21 | } 22 | } 23 | 24 | func BenchmarkInterfaceConvOnce(b *testing.B) { 25 | v := &Impl{} 26 | var vInterface Interface = v 27 | 28 | for i := 0; i < b.N; i++ { 29 | getI(vInterface) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /map-lookup-size/map_lookup_size_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | ) 8 | 9 | func getRandStrings(n int) []string { 10 | r := rand.New(rand.NewSource(1)) 11 | ss := make([]string, 0, n) 12 | unique := make(map[string]bool, n) 13 | for i := 0; i < n; i++ { 14 | s := getRandString(r) 15 | for unique[s] { 16 | s = getRandString(r) 17 | } 18 | 19 | ss = append(ss, s) 20 | unique[s] = true 21 | } 22 | 23 | return ss 24 | } 25 | 26 | var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 27 | 28 | func getRandString(r *rand.Rand) string { 29 | const length = 10 30 | 31 | buf := make([]byte, length) 32 | for i := range buf { 33 | buf[i] = chars[r.Intn(len(chars))] 34 | } 35 | return string(buf) 36 | } 37 | 38 | func BenchmarkLookups(b *testing.B) { 39 | strs := getRandStrings(1000000) 40 | perms := rand.Perm(len(strs)) 41 | 42 | for _, n := range []int{ 43 | 1000, 10000, 100000, 100000, 44 | } { 45 | m := make(map[string]int, n) 46 | for i := 0; i < n; i++ { 47 | m[strs[i]] = i 48 | } 49 | 50 | b.Run(fmt.Sprint(n), func(b *testing.B) { 51 | lookup(b, m, strs, perms) 52 | }) 53 | } 54 | } 55 | 56 | func lookup(b *testing.B, m map[string]int, allStrs []string, perms []int) { 57 | for i := 0; i < b.N; i++ { 58 | permIdx := i % (len(perms) - 1000) 59 | strs := allStrs[permIdx : permIdx+1000] 60 | for _, s := range strs { 61 | v := m[s] 62 | call(v) 63 | } 64 | } 65 | } 66 | 67 | func call(v int) {} 68 | -------------------------------------------------------------------------------- /map_contains_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkMapNoContains(b *testing.B) { 9 | for _, nKeys := range []int{100, 1000, 10000, 100000} { 10 | b.Run(fmt.Sprint(nKeys), func(b *testing.B) { 11 | m := make(map[int]struct{}, nKeys) 12 | for i := 0; i < b.N; i++ { 13 | k := i % nKeys 14 | if _, ok := m[k]; ok { 15 | continue 16 | } 17 | m[k] = struct{}{} 18 | } 19 | }) 20 | } 21 | } 22 | 23 | func BenchmarkMapContains(b *testing.B) { 24 | for _, nKeys := range []int{100, 1000, 10000, 100000} { 25 | b.Run(fmt.Sprint(nKeys), func(b *testing.B) { 26 | m := make(map[int]struct{}, nKeys) 27 | for i := 0; i < b.N; i++ { 28 | k := i % nKeys 29 | m[k] = struct{}{} 30 | } 31 | }) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /map_int/map_int_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "hash/crc32" 6 | "strconv" 7 | "testing" 8 | ) 9 | 10 | var _read Obj 11 | 12 | type Obj struct { 13 | Name string 14 | } 15 | 16 | func makeMap(n int) (_ map[int]Obj) { 17 | m := make(map[int]Obj, n) 18 | for i := 0; i < n; i++ { 19 | k := int(crc32.ChecksumIEEE([]byte(fmt.Sprint(i)))) 20 | m[k] = Obj{"test"} 21 | } 22 | return m 23 | } 24 | 25 | func keys(m map[int]Obj) []int { 26 | keys := make([]int, 0, len(m)) 27 | for k := range m { 28 | keys = append(keys, k) 29 | } 30 | return keys 31 | } 32 | 33 | func shuffle(keys []int) []int { 34 | return keys 35 | } 36 | 37 | func BenchmarkMapInt(b *testing.B) { 38 | for _, mapSize := range []int{100, 1000, 5000, 10000} { 39 | b.Run("Size-"+strconv.Itoa(mapSize), func(b *testing.B) { 40 | 41 | m := makeMap(mapSize) 42 | ks := keys(m) 43 | 44 | b.Run("Read", func(b *testing.B) { 45 | for i := 0; i < b.N; i++ { 46 | k := ks[i%len(ks)] 47 | _read = m[k] 48 | } 49 | }) 50 | 51 | new := Obj{"new"} 52 | b.Run("ReadWrite", func(b *testing.B) { 53 | for i := 0; i < b.N; i++ { 54 | k := ks[i%len(ks)] 55 | _read = m[k] 56 | m[k] = new 57 | } 58 | }) 59 | }) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /map_int/results-1.10: -------------------------------------------------------------------------------- 1 | go version go1.10 darwin/amd64 2 | goos: darwin 3 | goarch: amd64 4 | pkg: github.com/prashantv/go-bench/map_int 5 | BenchmarkMapInt/Size-100/Read-8 100000000 21.7 ns/op 6 | BenchmarkMapInt/Size-100/ReadWrite-8 30000000 38.2 ns/op 7 | BenchmarkMapInt/Size-1000/Read-8 50000000 23.1 ns/op 8 | BenchmarkMapInt/Size-1000/ReadWrite-8 50000000 38.0 ns/op 9 | BenchmarkMapInt/Size-5000/Read-8 100000000 23.6 ns/op 10 | BenchmarkMapInt/Size-5000/ReadWrite-8 50000000 37.8 ns/op 11 | BenchmarkMapInt/Size-10000/Read-8 100000000 23.1 ns/op 12 | BenchmarkMapInt/Size-10000/ReadWrite-8 50000000 37.6 ns/op 13 | PASS 14 | ok github.com/prashantv/go-bench/map_int 15.285s 15 | -------------------------------------------------------------------------------- /map_set_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkMapSetEmptyStruct(b *testing.B) { 6 | m := make(map[int]struct{}) 7 | 8 | for i := 0; i < b.N; i++ { 9 | want := false 10 | if i%5 == 0 { 11 | m[i] = struct{}{} 12 | want = true 13 | } 14 | if _, ok := m[i]; ok != want { 15 | panic("failed") 16 | } 17 | } 18 | } 19 | 20 | func BenchmarkMapSetBool(b *testing.B) { 21 | m := make(map[int]bool) 22 | 23 | for i := 0; i < b.N; i++ { 24 | want := false 25 | if i%5 == 0 { 26 | m[i] = true 27 | want = true 28 | } 29 | if _, ok := m[i]; ok != want { 30 | panic("failed") 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /map_vs_slice_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math/rand" 7 | "testing" 8 | ) 9 | 10 | func randKey() string { 11 | const n = 10 12 | const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 13 | bs := make([]byte, n) 14 | for i := range bs { 15 | bs[i] = letters[rand.Intn(len(letters))] 16 | } 17 | return string(bs) 18 | } 19 | 20 | func pickN(keys []string, n int) []string { 21 | newKeys := make([]string, n) 22 | for i := range newKeys { 23 | newKeys[i] = keys[rand.Intn(len(keys))] 24 | } 25 | return newKeys 26 | } 27 | 28 | var v string 29 | 30 | func benchmarkMap(b *testing.B, n int) { 31 | m := make(map[string]string, n) 32 | keys := make([]string, n) 33 | for i := 0; i < n; i++ { 34 | k := randKey() 35 | m[k] = k 36 | 37 | keys[i] = k 38 | } 39 | keys = pickN(keys, 10) 40 | 41 | b.ResetTimer() 42 | 43 | for i := 0; i < b.N; i++ { 44 | v = m["not-found"] 45 | for _, k := range keys { 46 | v = m[k] 47 | } 48 | } 49 | b.StopTimer() 50 | fmt.Fprintf(ioutil.Discard, v) 51 | } 52 | 53 | type entry struct { 54 | key, value string 55 | } 56 | 57 | func lookup(entries []entry, key string) string { 58 | for i := range entries { 59 | if entries[i].key == key { 60 | return entries[i].value 61 | } 62 | } 63 | return "" 64 | } 65 | 66 | func benchmarkSlice(b *testing.B, n int) { 67 | keys := make([]string, n) 68 | s := make([]entry, n) 69 | for i := range s { 70 | s[i].key = randKey() 71 | s[i].value = s[i].key 72 | keys[i] = s[i].key 73 | } 74 | keys = pickN(keys, 10) 75 | 76 | b.ResetTimer() 77 | 78 | for i := 0; i < b.N; i++ { 79 | v = lookup(s, "not-found") 80 | for _, k := range keys { 81 | v = lookup(s, k) 82 | } 83 | } 84 | b.StopTimer() 85 | fmt.Fprintf(ioutil.Discard, v) 86 | } 87 | 88 | func BenchmarkMap1(b *testing.B) { benchmarkMap(b, 1) } 89 | func BenchmarkSlice1(b *testing.B) { benchmarkSlice(b, 1) } 90 | 91 | func BenchmarkMap2(b *testing.B) { benchmarkMap(b, 2) } 92 | func BenchmarkSlice2(b *testing.B) { benchmarkSlice(b, 2) } 93 | 94 | func BenchmarkMap4(b *testing.B) { benchmarkMap(b, 4) } 95 | func BenchmarkSlice4(b *testing.B) { benchmarkSlice(b, 4) } 96 | 97 | func BenchmarkMap10(b *testing.B) { benchmarkMap(b, 10) } 98 | func BenchmarkSlice10(b *testing.B) { benchmarkSlice(b, 10) } 99 | 100 | func BenchmarkMap20(b *testing.B) { benchmarkMap(b, 20) } 101 | func BenchmarkSlice20(b *testing.B) { benchmarkSlice(b, 20) } 102 | 103 | func BenchmarkMap40(b *testing.B) { benchmarkMap(b, 40) } 104 | func BenchmarkSlice40(b *testing.B) { benchmarkSlice(b, 40) } 105 | 106 | func BenchmarkMap100(b *testing.B) { benchmarkMap(b, 100) } 107 | func BenchmarkSlice100(b *testing.B) { benchmarkSlice(b, 100) } 108 | 109 | func BenchmarkMap500(b *testing.B) { benchmarkMap(b, 500) } 110 | func BenchmarkSlice500(b *testing.B) { benchmarkSlice(b, 500) } 111 | -------------------------------------------------------------------------------- /maplookup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // MapOfMap is a map that has anotehr map as a value. 4 | type MapOfMap map[string]map[string]interface{} 5 | 6 | // GetWithOkCheck checks whether the first key exists using the v, ok lookup return. 7 | func (m MapOfMap) GetWithOkCheck(k1, k2 string) interface{} { 8 | if innerMap, ok := m[k1]; ok { 9 | return innerMap[k2] 10 | } 11 | return nil 12 | } 13 | 14 | // GetWithCheck checks whether the first key exists by checking if the value is nil. 15 | func (m MapOfMap) GetWithCheck(k1, k2 string) interface{} { 16 | if innerMap := m[k1]; innerMap != nil { 17 | return innerMap[k2] 18 | } 19 | return nil 20 | } 21 | 22 | // Get does not do any checks and relies on nil map lookup. 23 | func (m MapOfMap) Get(k1, k2 string) interface{} { 24 | return m[k1][k2] 25 | } 26 | -------------------------------------------------------------------------------- /maplookup_results.md: -------------------------------------------------------------------------------- 1 | ## Maplookup Results 2 | 3 | Benchmark Name|Iterations|Per-Iteration 4 | ----|----|---- 5 | BenchmarkGetWithOkCheck| 1000000| 2172 ns/op 6 | BenchmarkGetWithCheck| 1000000| 2137 ns/op 7 | BenchmarkGet| 1000000| 2134 ns/op 8 | 9 | Generated using go version go1.4.2 darwin/amd64 10 | -------------------------------------------------------------------------------- /maplookup_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | // The following constants control the ratio of successful lookups where 9 | // values exist, to lookups where the value does not exist. 10 | const ( 11 | successLookups = 1 12 | failureLookups = 1 13 | ) 14 | 15 | func makeInnerMap(prefix string) map[string]interface{} { 16 | m := make(map[string]interface{}) 17 | m[prefix+"1"] = 1 18 | m[prefix+"2"] = 2 19 | m[prefix+"3"] = 3 20 | return m 21 | } 22 | 23 | func buildMap() MapOfMap { 24 | m := make(MapOfMap) 25 | m["1"] = makeInnerMap("1") 26 | m["2"] = makeInnerMap("2") 27 | m["3"] = makeInnerMap("3") 28 | return m 29 | } 30 | 31 | func doTest(b *testing.B, f func(k1, k2 string) interface{}) { 32 | tests := []struct { 33 | k1 string 34 | k2 string 35 | val interface{} 36 | }{ 37 | {"1", "11", 1}, 38 | {"1", "13", 3}, 39 | {"2", "21", 1}, 40 | {"2", "22", 2}, 41 | {"3", "32", 2}, 42 | {"3", "33", 3}, 43 | } 44 | 45 | for _, tt := range tests { 46 | for i := 0; i < successLookups; i++ { 47 | if got := f(tt.k1, tt.k2); got != tt.val { 48 | b.Errorf("Lookup[%v, %v] got %v, want %v", tt.k1, tt.k2, got, tt.val) 49 | } 50 | } 51 | for i := 0; i < failureLookups; i++ { 52 | if f(tt.k1+fmt.Sprint(i), tt.k2) != nil { 53 | b.Errorf("Lookup[%v, %v] got something other than nil", tt.k1, tt.k2) 54 | } 55 | } 56 | } 57 | } 58 | 59 | func BenchmarkGetWithOkCheck(b *testing.B) { 60 | m := buildMap() 61 | b.ResetTimer() 62 | for i := 0; i < b.N; i++ { 63 | doTest(b, m.GetWithOkCheck) 64 | } 65 | } 66 | 67 | func BenchmarkGetWithCheck(b *testing.B) { 68 | m := buildMap() 69 | b.ResetTimer() 70 | for i := 0; i < b.N; i++ { 71 | doTest(b, m.GetWithCheck) 72 | } 73 | } 74 | 75 | func BenchmarkGet(b *testing.B) { 76 | m := buildMap() 77 | b.ResetTimer() 78 | for i := 0; i < b.N; i++ { 79 | doTest(b, m.Get) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /mod_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkMod(b *testing.B) { 9 | var got int 10 | for i := 0; i < b.N; i++ { 11 | got = i % 2 12 | } 13 | fmt.Println(got) 14 | } 15 | 16 | func BenchmarkAnd(b *testing.B) { 17 | var got int 18 | for i := 0; i < b.N; i++ { 19 | got = i & 1 20 | } 21 | fmt.Println(got) 22 | } 23 | -------------------------------------------------------------------------------- /mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "sync" 4 | 5 | // Test for overhead and alternatives to defer. 6 | // See http://lk4d4.darth.io/posts/defer/ 7 | 8 | // SyncVal is a value protected by an interface. 9 | type SyncVal struct { 10 | sync.Mutex 11 | v interface{} 12 | } 13 | 14 | // PutSimple gets a lock and unlocks it explicitly after the operation. 15 | func (sv *SyncVal) PutSimple(v interface{}) { 16 | sv.Lock() 17 | sv.v = v 18 | sv.Unlock() 19 | } 20 | 21 | // PutDefer uses a defer to lock and unlock the mutex. 22 | func (sv *SyncVal) PutDefer(v interface{}) { 23 | sv.Lock() 24 | defer sv.Unlock() 25 | 26 | sv.v = v 27 | } 28 | 29 | func (sv *SyncVal) withMutex(f func()) { 30 | sv.Lock() 31 | f() 32 | sv.Unlock() 33 | } 34 | 35 | // PutFunc uses a function to lock and unlock. 36 | func (sv *SyncVal) PutFunc(v interface{}) { 37 | sv.withMutex(func() { 38 | sv.v = v 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /mutex_results.md: -------------------------------------------------------------------------------- 1 | ## Mutex Results 2 | 3 | Benchmark Name|Iterations|Per-Iteration 4 | ----|----|---- 5 | BenchmarkPutSimple|30000000| 53.4 ns/op 6 | BenchmarkPutDefer|10000000| 135 ns/op 7 | BenchmarkPutFunc|30000000| 56.3 ns/op 8 | 9 | Generated using go version go1.4.2 darwin/amd64 10 | -------------------------------------------------------------------------------- /mutex_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | sv = &SyncVal{} 10 | mutexInt int 11 | ) 12 | 13 | func BenchmarkPutSimple(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | sv.PutSimple(i) 16 | } 17 | } 18 | 19 | func BenchmarkPutDefer(b *testing.B) { 20 | for i := 0; i < b.N; i++ { 21 | sv.PutDefer(i) 22 | } 23 | } 24 | 25 | func BenchmarkPutFunc(b *testing.B) { 26 | for i := 0; i < b.N; i++ { 27 | sv.PutFunc(i) 28 | } 29 | } 30 | 31 | func BenchmarkRLock(b *testing.B) { 32 | var s sync.RWMutex 33 | b.RunParallel(func(pb *testing.PB) { 34 | for pb.Next() { 35 | s.RLock() 36 | _ = mutexInt 37 | s.RLock() 38 | } 39 | }) 40 | } 41 | 42 | func BenchmarkLock(b *testing.B) { 43 | var s sync.Mutex 44 | b.RunParallel(func(pb *testing.PB) { 45 | for pb.Next() { 46 | s.Lock() 47 | _ = mutexInt 48 | s.Unlock() 49 | } 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /new_bench_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "testing" 7 | ) 8 | 9 | type User struct { 10 | name string 11 | age int 12 | foo string 13 | } 14 | 15 | func BenchmarkNewKeyword(b *testing.B) { 16 | var u *User 17 | for i := 0; i < b.N; i++ { 18 | u = new(User) 19 | } 20 | fmt.Fprintln(ioutil.Discard, u) 21 | } 22 | 23 | func BenchmarkNewInline(b *testing.B) { 24 | var u *User 25 | for i := 0; i < b.N; i++ { 26 | u = &User{} 27 | } 28 | fmt.Fprintln(ioutil.Discard, u) 29 | } 30 | -------------------------------------------------------------------------------- /rand_bench_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "math/rand" 5 | "sync" 6 | "sync/atomic" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | type Rand interface { 12 | Intn(n int) int 13 | } 14 | 15 | func benchmarkRand(b *testing.B, r Rand) { 16 | b.ResetTimer() 17 | b.SetParallelism(20) 18 | 19 | b.RunParallel(func(pb *testing.PB) { 20 | for pb.Next() { 21 | r.Intn(4) 22 | r.Intn(10) 23 | r.Intn(20) 24 | r.Intn(1000) 25 | } 26 | }) 27 | } 28 | 29 | type globalRand struct{} 30 | 31 | func (globalRand) Intn(n int) int { 32 | return rand.Intn(n) 33 | } 34 | 35 | type roundRobinRand struct { 36 | rands []*rand.Rand 37 | cur int32 38 | } 39 | 40 | type lockedSource struct { 41 | lk sync.Mutex 42 | src rand.Source 43 | } 44 | 45 | func (r *lockedSource) Int63() (n int64) { 46 | r.lk.Lock() 47 | n = r.src.Int63() 48 | r.lk.Unlock() 49 | return 50 | } 51 | 52 | func (r *lockedSource) Seed(seed int64) { 53 | r.lk.Lock() 54 | r.src.Seed(seed) 55 | r.lk.Unlock() 56 | } 57 | 58 | func newRoundRobinRand(count int) Rand { 59 | rr := &roundRobinRand{ 60 | rands: make([]*rand.Rand, count), 61 | } 62 | for i := 0; i < count; i++ { 63 | rr.rands[i] = rand.New( 64 | &lockedSource{src: rand.NewSource(time.Now().UnixNano())}, 65 | ) 66 | } 67 | return rr 68 | } 69 | 70 | func (r *roundRobinRand) Intn(n int) int { 71 | i := atomic.AddInt32(&r.cur, 1) 72 | return r.rands[int(i)%len(r.rands)].Intn(n) 73 | } 74 | 75 | func BenchmarkGlobalRand(b *testing.B) { 76 | benchmarkRand(b, globalRand{}) 77 | } 78 | 79 | func BenchmarkRoundRobinRand10(b *testing.B) { 80 | benchmarkRand(b, newRoundRobinRand(10)) 81 | } 82 | 83 | func BenchmarkRoundRobinRand100(b *testing.B) { 84 | benchmarkRand(b, newRoundRobinRand(100)) 85 | } 86 | 87 | func BenchmarkRandSingle(b *testing.B) { 88 | for i := 0; i < b.N; i++ { 89 | rand.Intn(4) 90 | rand.Intn(10) 91 | rand.Intn(20) 92 | rand.Intn(1000) 93 | } 94 | } 95 | 96 | type timeRand struct{} 97 | 98 | // Probably not a good idea when n > 10. 99 | func (timeRand) Intn(n int) int { 100 | return int(time.Now().UnixNano()) % n 101 | } 102 | 103 | func BenchmarkTimeNowRand(b *testing.B) { 104 | benchmarkRand(b, timeRand{}) 105 | } 106 | 107 | // Get processor-local counter? 108 | // Atomic operations for processors (faster!) 109 | // Fast rand would 110 | 111 | // TODO: 112 | // what if there was a processor-local atomic? 113 | // basically, you get returned the processor ID. 114 | // and you can manage the array safely. 115 | // maybe it should always increment and return? 116 | -------------------------------------------------------------------------------- /ratelimit/interface.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | // RateLimiter is the interface implemented by a rate limiter. 4 | type RateLimiter interface { 5 | // Take should block to make sure that the RPS is met. 6 | Take() 7 | } 8 | -------------------------------------------------------------------------------- /ratelimit/locked_counter.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | // lockedCounter implements rate limiting using a token bucket. 9 | // The bucket is locked using a mutex, and uses sync.Cond to 10 | // signal waiters. 11 | type lockedCounter struct { 12 | sync.Mutex 13 | cond *sync.Cond 14 | n int 15 | rps int 16 | } 17 | 18 | func newLockedCounter(rps int) *lockedCounter { 19 | c := &lockedCounter{rps: rps} 20 | c.cond = sync.NewCond(c) 21 | go c.filler() 22 | return c 23 | } 24 | 25 | func (c *lockedCounter) filler() { 26 | const numPeriods = 1000 27 | 28 | increment := c.rps / numPeriods 29 | sleepFor := time.Second / numPeriods 30 | 31 | for i := 0; true; i++ { 32 | if i == numPeriods { 33 | i = 0 34 | c.Lock() 35 | c.n = increment 36 | c.Unlock() 37 | 38 | } else { 39 | c.Lock() 40 | c.n += increment 41 | c.Unlock() 42 | } 43 | 44 | c.cond.Broadcast() 45 | time.Sleep(sleepFor) 46 | } 47 | } 48 | 49 | func (c *lockedCounter) Take() { 50 | c.Lock() 51 | defer c.Unlock() 52 | 53 | if c.n > 0 { 54 | c.n-- 55 | return 56 | } 57 | 58 | for c.n <= 0 { 59 | c.cond.Wait() 60 | } 61 | c.n-- 62 | } 63 | -------------------------------------------------------------------------------- /ratelimit/ratelimit_test.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "fmt" 5 | "sync/atomic" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestRateLimit(t *testing.T) { 11 | const numGoRoutines = 5 12 | 13 | l := newTimePeriod(50000) 14 | 15 | var rps int32 16 | go func() { 17 | for { 18 | time.Sleep(time.Second) 19 | v := atomic.SwapInt32(&rps, 0) 20 | fmt.Println("\nRPS", v) 21 | } 22 | }() 23 | 24 | for i := 0; i < numGoRoutines; i++ { 25 | go func() { 26 | c := 0 27 | for { 28 | l.Take() 29 | atomic.AddInt32(&rps, 1) 30 | c++ 31 | if c == 400 { 32 | fmt.Printf(".") 33 | c = 0 34 | } 35 | } 36 | }() 37 | } 38 | select {} 39 | } 40 | -------------------------------------------------------------------------------- /ratelimit/time_period.go: -------------------------------------------------------------------------------- 1 | package ratelimit 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | type timePeriod struct { 9 | sync.Mutex 10 | last time.Time 11 | sleepFor time.Duration 12 | perRequest time.Duration 13 | } 14 | 15 | func newTimePeriod(rps int) *timePeriod { 16 | return &timePeriod{ 17 | perRequest: time.Second / time.Duration(rps), 18 | } 19 | } 20 | 21 | func (t *timePeriod) Take() { 22 | t.Lock() 23 | defer t.Unlock() 24 | 25 | // If this is our first request, then we allow it. 26 | cur := time.Now() 27 | if t.last.IsZero() { 28 | t.last = cur 29 | return 30 | } 31 | 32 | // sleepFor calculates how much time we should sleep based on 33 | // the perRequest budget and how long the last request took. 34 | // Since the request may take longer than the budget, this number 35 | // can get negative, and is summed across requests. 36 | t.sleepFor = t.sleepFor + t.perRequest - cur.Sub(t.last) 37 | t.last = cur 38 | 39 | // We shouldn't allow sleepFor to get too negative, since it would mean that 40 | // a service that slowed down a lot for a short period of time would get 41 | // a much higher RPS following that. 42 | if t.sleepFor < -time.Second { 43 | t.sleepFor = time.Second 44 | } 45 | 46 | // If sleepFor is positive, then we should sleep now. 47 | if t.sleepFor > 0 { 48 | time.Sleep(t.sleepFor) 49 | t.last = cur.Add(t.sleepFor) 50 | t.sleepFor = 0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /receiver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | ) 7 | 8 | type emptyType struct{} 9 | 10 | func (emptyType) Call() { 11 | fmt.Fprintln(ioutil.Discard, "1") 12 | } 13 | 14 | func (e *emptyType) CallPointer() { 15 | fmt.Fprintln(ioutil.Discard, "2") 16 | } 17 | -------------------------------------------------------------------------------- /receiver_results.md: -------------------------------------------------------------------------------- 1 | ## Receiver Results 2 | 3 | Benchmark Name|Iterations|Per-Iteration 4 | ----|----|---- 5 | BenchmarkCall| 500000| 2408 ns/op 6 | BenchmarkCallPointer| 500000| 2451 ns/op 7 | 8 | Generated using go version go1.4.2 darwin/amd64 9 | -------------------------------------------------------------------------------- /receiver_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkCall(b *testing.B) { 6 | var e emptyType 7 | for i := 0; i < b.N; i++ { 8 | e.Call() 9 | e.Call() 10 | e.Call() 11 | e.Call() 12 | e.Call() 13 | e.Call() 14 | e.Call() 15 | e.Call() 16 | e.Call() 17 | e.Call() 18 | e.Call() 19 | e.Call() 20 | e.Call() 21 | e.Call() 22 | e.Call() 23 | } 24 | } 25 | 26 | func BenchmarkCallPointer(b *testing.B) { 27 | e := &emptyType{} 28 | for i := 0; i < b.N; i++ { 29 | e.CallPointer() 30 | e.CallPointer() 31 | e.CallPointer() 32 | e.CallPointer() 33 | e.CallPointer() 34 | e.CallPointer() 35 | e.CallPointer() 36 | e.CallPointer() 37 | e.CallPointer() 38 | e.CallPointer() 39 | e.CallPointer() 40 | e.CallPointer() 41 | e.CallPointer() 42 | e.CallPointer() 43 | e.CallPointer() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scripts/markdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | TEST=$1 4 | TEST="$(tr '[:lower:]' '[:upper:]' <<< ${TEST:0:1})${TEST:1}" 5 | 6 | echo "## $TEST Results" 7 | echo 8 | echo "Benchmark Name|Iterations|Per-Iteration" 9 | echo "----|----|----" 10 | grep Benchmark \ 11 | | tr '\t' '|' 12 | 13 | GOVERSION=$(go version) 14 | echo 15 | echo "Generated using $GOVERSION" 16 | -------------------------------------------------------------------------------- /sort/bench.out: -------------------------------------------------------------------------------- 1 | goos: darwin 2 | goarch: arm64 3 | pkg: github.com/prashantv/go-bench/sort 4 | BenchmarkSortReverse/slices/size=1 281369086 4.216 ns/op 0 B/op 0 allocs/op 5 | BenchmarkSortReverse/sortIface/size=1 36486592 33.26 ns/op 32 B/op 1 allocs/op 6 | BenchmarkSortReverse/slices/size=10 12616046 95.06 ns/op 0 B/op 0 allocs/op 7 | BenchmarkSortReverse/sortIface/size=10 4790110 249.1 ns/op 32 B/op 1 allocs/op 8 | BenchmarkSortReverse/slices/size=100 4285416 279.3 ns/op 0 B/op 0 allocs/op 9 | BenchmarkSortReverse/sortIface/size=100 2742613 437.1 ns/op 32 B/op 1 allocs/op 10 | BenchmarkSortReverse/slices/size=1000 486651 2447 ns/op 0 B/op 0 allocs/op 11 | BenchmarkSortReverse/sortIface/size=1000 326660 3619 ns/op 32 B/op 1 allocs/op 12 | BenchmarkSortRandom/slices/size=1 241160948 4.968 ns/op 0 B/op 0 allocs/op 13 | BenchmarkSortRandom/sortIface/size=1 50213844 24.09 ns/op 24 B/op 1 allocs/op 14 | BenchmarkSortRandom/slices/size=10 15208659 78.26 ns/op 0 B/op 0 allocs/op 15 | BenchmarkSortRandom/sortIface/size=10 7589322 156.2 ns/op 24 B/op 1 allocs/op 16 | BenchmarkSortRandom/slices/size=100 892729 1316 ns/op 0 B/op 0 allocs/op 17 | BenchmarkSortRandom/sortIface/size=100 635828 1855 ns/op 24 B/op 1 allocs/op 18 | BenchmarkSortRandom/slices/size=1000 32025 33980 ns/op 0 B/op 0 allocs/op 19 | BenchmarkSortRandom/sortIface/size=1000 28688 40778 ns/op 24 B/op 1 allocs/op 20 | BenchmarkSortedList/slices/size=1 321529766 3.738 ns/op 0 B/op 0 allocs/op 21 | BenchmarkSortedList/sortIface/size=1 51364822 22.75 ns/op 24 B/op 1 allocs/op 22 | BenchmarkSortedList/slices/size=10 65038738 18.39 ns/op 0 B/op 0 allocs/op 23 | BenchmarkSortedList/sortIface/size=10 24258392 48.07 ns/op 24 B/op 1 allocs/op 24 | BenchmarkSortedList/slices/size=100 4916845 243.9 ns/op 0 B/op 0 allocs/op 25 | BenchmarkSortedList/sortIface/size=100 4307540 277.0 ns/op 24 B/op 1 allocs/op 26 | BenchmarkSortedList/slices/size=1000 544494 2215 ns/op 0 B/op 0 allocs/op 27 | BenchmarkSortedList/sortIface/size=1000 499792 2276 ns/op 24 B/op 1 allocs/op 28 | PASS 29 | ok github.com/prashantv/go-bench/sort 32.797s 30 | -------------------------------------------------------------------------------- /sort/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prashantv/go-bench/sort 2 | 3 | go 1.21.1 4 | -------------------------------------------------------------------------------- /sort/prof.mem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prashantv/go-bench/fa11c87141166e987603ffb0f32a8a6e4dcb2838/sort/prof.mem -------------------------------------------------------------------------------- /sort/sorted_list_test.go: -------------------------------------------------------------------------------- 1 | package sort 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "slices" 7 | "sort" 8 | "testing" 9 | ) 10 | 11 | func sortInterface(ints []int) { 12 | sort.Ints(ints) 13 | } 14 | 15 | func sortInterfaceReverse(ints []int) { 16 | sort.Sort(sort.Reverse(sort.IntSlice(ints))) 17 | } 18 | 19 | func slicesSort(ints []int) { 20 | slices.SortFunc(ints, func(a, b int) int { 21 | return a - b 22 | }) 23 | } 24 | 25 | func slicesSortReverse(ints []int) { 26 | slices.SortFunc(ints, func(a, b int) int { 27 | return b - a 28 | }) 29 | } 30 | 31 | func BenchmarkSortReverse(b *testing.B) { 32 | for _, size := range []int{1, 10, 100, 1000} { 33 | elements := make([]int, size) 34 | for i := range elements { 35 | elements[i] = i 36 | } 37 | 38 | b.Run(fmt.Sprintf("slices/size=%d", size), func(b *testing.B) { 39 | for i := 0; i < b.N; i++ { 40 | if i%2 == 0 { 41 | slicesSortReverse(elements) 42 | } else { 43 | slicesSort(elements) 44 | } 45 | } 46 | }) 47 | 48 | b.Run(fmt.Sprintf("sortIface/size=%d", size), func(b *testing.B) { 49 | for i := 0; i < b.N; i++ { 50 | if i%2 == 0 { 51 | sortInterfaceReverse(elements) 52 | } else { 53 | sortInterface(elements) 54 | } 55 | } 56 | }) 57 | } 58 | } 59 | 60 | func BenchmarkSortRandom(b *testing.B) { 61 | for _, size := range []int{1, 10, 100, 1000} { 62 | orig := rand.Perm(size) 63 | elements := make([]int, size) 64 | b.Run(fmt.Sprintf("slices/size=%d", size), func(b *testing.B) { 65 | for i := 0; i < b.N; i++ { 66 | copy(elements, orig) 67 | slicesSort(elements) 68 | } 69 | }) 70 | 71 | b.Run(fmt.Sprintf("sortIface/size=%d", size), func(b *testing.B) { 72 | for i := 0; i < b.N; i++ { 73 | copy(elements, orig) 74 | sortInterface(elements) 75 | } 76 | }) 77 | } 78 | } 79 | 80 | func BenchmarkSortedList(b *testing.B) { 81 | for _, size := range []int{1, 10, 100, 1000} { 82 | elements := make([]int, size) 83 | for i := range elements { 84 | elements[i] = i 85 | } 86 | b.Run(fmt.Sprintf("slices/size=%d", size), func(b *testing.B) { 87 | for i := 0; i < b.N; i++ { 88 | slicesSort(elements) 89 | } 90 | }) 91 | 92 | b.Run(fmt.Sprintf("sortIface/size=%d", size), func(b *testing.B) { 93 | for i := 0; i < b.N; i++ { 94 | sortInterface(elements) 95 | } 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /sorted_vs_heap/bench.out: -------------------------------------------------------------------------------- 1 | goos: linux 2 | goarch: amd64 3 | pkg: github.com/prashantv/go-bench/sorted_vs_heap 4 | cpu: 13th Gen Intel(R) Core(TM) i5-13600KF 5 | BenchmarkSorted/1_shuffled_elems 135462193 8.954 ns/op 8 B/op 0 allocs/op 6 | BenchmarkSorted/1_sorted_elems 131403879 9.294 ns/op 8 B/op 0 allocs/op 7 | BenchmarkSorted/10_shuffled_elems 5600216 213.8 ns/op 80 B/op 1 allocs/op 8 | BenchmarkSorted/10_sorted_elems 7411904 162.9 ns/op 80 B/op 1 allocs/op 9 | BenchmarkSorted/100_shuffled_elems 58149 20709 ns/op 1536 B/op 1 allocs/op 10 | BenchmarkSorted/100_sorted_elems 135169 8900 ns/op 1536 B/op 1 allocs/op 11 | BenchmarkSorted/1000_shuffled_elems 1035 1153140 ns/op 17922 B/op 3 allocs/op 12 | BenchmarkSorted/1000_sorted_elems 1855 635705 ns/op 17921 B/op 3 allocs/op 13 | BenchmarkHeap/1_shuffled_elems 100000000 11.20 ns/op 0 B/op 0 allocs/op 14 | BenchmarkHeap/1_sorted_elems 100000000 10.70 ns/op 0 B/op 0 allocs/op 15 | BenchmarkHeap/10_shuffled_elems 7505498 159.1 ns/op 0 B/op 0 allocs/op 16 | BenchmarkHeap/10_sorted_elems 8234262 143.1 ns/op 0 B/op 0 allocs/op 17 | BenchmarkHeap/100_shuffled_elems 449350 2648 ns/op 0 B/op 0 allocs/op 18 | BenchmarkHeap/100_sorted_elems 498121 2350 ns/op 0 B/op 0 allocs/op 19 | BenchmarkHeap/1000_shuffled_elems 17224 70197 ns/op 1 B/op 0 allocs/op 20 | BenchmarkHeap/1000_sorted_elems 20263 59578 ns/op 1 B/op 0 allocs/op 21 | PASS 22 | ok github.com/prashantv/go-bench/sorted_vs_heap 23.336s 23 | -------------------------------------------------------------------------------- /sorted_vs_heap/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/prashantv/go-bench/sorted_vs_heap 2 | 3 | go 1.21.1 4 | 5 | require github.com/stretchr/testify v1.8.4 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /sorted_vs_heap/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 6 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /sorted_vs_heap/sorted_vs_heap_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "cmp" 5 | "container/heap" 6 | "fmt" 7 | "math/rand" 8 | "slices" 9 | "sort" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | type sortedSlice []int 16 | 17 | func newSortedSlice() *sortedSlice { return &sortedSlice{} } 18 | func (ss sortedSlice) Len() int { return len(ss) } 19 | func (ss sortedSlice) Less(i, j int) bool { return ss[i] < ss[j] } 20 | func (ss sortedSlice) Swap(i, j int) { ss[i], ss[j] = ss[j], ss[i] } 21 | 22 | func (ss *sortedSlice) PushV(v int) { 23 | if cap(*ss) == 0 { 24 | *ss = make(sortedSlice, 0, 10) 25 | } 26 | *ss = append(*ss, v) 27 | sort.Sort(ss) 28 | } 29 | 30 | func (ss *sortedSlice) PopV() int { 31 | v := (*ss)[0] 32 | *ss = (*ss)[1:] 33 | return v 34 | } 35 | 36 | type sortedSliceGen []int 37 | 38 | func newSortedSliceGen() *sortedSliceGen { return &sortedSliceGen{} } 39 | func (ss sortedSliceGen) Len() int { return len(ss) } 40 | func (ss *sortedSliceGen) PushV(v int) { 41 | if cap(*ss) == 0 { 42 | *ss = make(sortedSliceGen, 0, 10) 43 | } 44 | *ss = append(*ss, v) 45 | slices.SortFunc(*ss, func(a, b int) int { 46 | return cmp.Compare(a, b) 47 | }) 48 | } 49 | 50 | func (ss *sortedSliceGen) PopV() int { 51 | v := (*ss)[0] 52 | *ss = (*ss)[1:] 53 | return v 54 | } 55 | 56 | type heapSlice struct { 57 | values []int 58 | arg int 59 | } 60 | 61 | func newHeapSlice() *heapSlice { return &heapSlice{} } 62 | func (h heapSlice) Len() int { return len(h.values) } 63 | func (h heapSlice) Less(i, j int) bool { return h.values[i] < h.values[j] } 64 | func (h heapSlice) Swap(i, j int) { h.values[i], h.values[j] = h.values[j], h.values[i] } 65 | 66 | func (h *heapSlice) Push(v any) { 67 | h.values = append(h.values, h.arg) 68 | } 69 | 70 | func (h *heapSlice) Pop() any { 71 | n := len(h.values) 72 | h.arg = h.values[n-1] 73 | h.values = h.values[0 : n-1] 74 | return 0 75 | } 76 | 77 | func (h *heapSlice) PushV(v int) { 78 | h.arg = v 79 | heap.Push(h, 0) 80 | } 81 | 82 | func (h *heapSlice) PopV() int { 83 | heap.Pop(h) 84 | return h.arg 85 | } 86 | 87 | type Stack interface { 88 | PushV(v int) 89 | PopV() int 90 | Len() int 91 | } 92 | 93 | func BenchmarkSorted(b *testing.B) { 94 | runBenchmarks[*sortedSlice](b, newSortedSlice) 95 | } 96 | 97 | func BenchmarkSortedGen(b *testing.B) { 98 | runBenchmarks[*sortedSliceGen](b, newSortedSliceGen) 99 | } 100 | 101 | func TestSorted(t *testing.T) { 102 | runTests[*sortedSlice](t, newSortedSlice) 103 | } 104 | 105 | func TestSortedGenerics(t *testing.T) { 106 | runTests[*sortedSliceGen](t, newSortedSliceGen) 107 | } 108 | 109 | func BenchmarkHeap(b *testing.B) { 110 | runBenchmarks[*heapSlice](b, newHeapSlice) 111 | } 112 | 113 | func TestHeap(t *testing.T) { 114 | runTests[*heapSlice](t, newHeapSlice) 115 | } 116 | 117 | func runBenchmarks[S Stack](b *testing.B, newFn func() S) { 118 | for _, numElems := range []int{1, 10, 100, 1000} { 119 | elems := randElems(numElems) 120 | b.Run(fmt.Sprintf("%v shuffled elems", numElems), func(b *testing.B) { 121 | s := newFn() 122 | for i := 0; i < b.N; i++ { 123 | for _, v := range elems { 124 | s.PushV(v) 125 | } 126 | for range elems { 127 | s.PopV() 128 | } 129 | } 130 | }) 131 | 132 | b.Run(fmt.Sprintf("%v sorted elems", numElems), func(b *testing.B) { 133 | s := newFn() 134 | for i := 0; i < b.N; i++ { 135 | for j := 0; j < numElems; j++ { 136 | s.PushV(j) 137 | } 138 | for j := 0; j < numElems; j++ { 139 | s.PopV() 140 | } 141 | } 142 | }) 143 | } 144 | } 145 | 146 | func runTests[S Stack](t *testing.T, newFn func() S) { 147 | t.Run("single element", func(t *testing.T) { 148 | s := newFn() 149 | for i := 0; i < 100; i++ { 150 | s.PushV(i) 151 | assert.Equal(t, 1, s.Len()) 152 | assert.Equal(t, i, s.PopV()) 153 | assert.Equal(t, 0, s.Len()) 154 | } 155 | }) 156 | 157 | t.Run("multiple push/pop", func(t *testing.T) { 158 | push := []int{10, 5, 6, 3, 2, 8, 4, 9, 7, 1, 0} 159 | s := newFn() 160 | for _, v := range push { 161 | s.PushV(v) 162 | } 163 | 164 | // Pop some elements 165 | for i := 0; i < 5; i++ { 166 | assert.Equal(t, i, s.PopV()) 167 | } 168 | 169 | // Then push them back 170 | for i := 0; i < 5; i++ { 171 | s.PushV(4 - i) 172 | } 173 | 174 | // Push all 175 | for i := 0; i < 10; i++ { 176 | assert.Equal(t, i, s.PopV()) 177 | } 178 | }) 179 | } 180 | 181 | func randElems(n int) []int { 182 | // Deterministic element ordering 183 | r := rand.New(rand.NewSource(1)) 184 | 185 | var elems []int 186 | for i := 0; i < n; i++ { 187 | elems = append(elems, i) 188 | } 189 | r.Shuffle(len(elems), func(i, j int) { 190 | elems[i], elems[j] = elems[j], elems[i] 191 | }) 192 | return elems 193 | } 194 | -------------------------------------------------------------------------------- /string_append_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var val = "value" 9 | var _resultStr string 10 | 11 | func BenchmarkStringAppendSprintf(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | _resultStr = fmt.Sprintf("%s.appended", val) 14 | } 15 | } 16 | 17 | func BenchmarkStringAppendAdd(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | _resultStr = val + ".appended" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /string_cast_bench_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | "unsafe" 7 | ) 8 | 9 | func hash(bs []byte) int { 10 | sum := 0 11 | for _, b := range bs { 12 | sum += int(b) 13 | } 14 | return sum 15 | } 16 | 17 | func BenchmarkHashStringCast(b *testing.B) { 18 | s := "str" 19 | b.ResetTimer() 20 | for i := 0; i < b.N; i++ { 21 | hash([]byte(s)) 22 | } 23 | } 24 | 25 | func BenchmarkHashStringUnsafe(b *testing.B) { 26 | s := "str" 27 | b.ResetTimer() 28 | for i := 0; i < b.N; i++ { 29 | hash(unsafeStrToByte(s)) 30 | } 31 | } 32 | 33 | func BenchmarkHashBytes(b *testing.B) { 34 | s := []byte("str") 35 | for i := 0; i < b.N; i++ { 36 | hash(s) 37 | } 38 | } 39 | 40 | func unsafeStrToByte(s string) []byte { 41 | strHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) 42 | byteHeader := reflect.SliceHeader{ 43 | Data: strHeader.Data, 44 | Len: strHeader.Len, 45 | Cap: strHeader.Len, 46 | } 47 | return *(*[]byte)(unsafe.Pointer(&byteHeader)) 48 | } 49 | -------------------------------------------------------------------------------- /string_compare_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | _emptyString = "" 10 | _notEmptyString = strings.Repeat("test", 1000) 11 | _boolResult bool 12 | ) 13 | 14 | func BenchmarkCompareStringEmpty(b *testing.B) { 15 | for i := 0; i < b.N; i++ { 16 | _boolResult = (_emptyString == "") 17 | _boolResult = (_notEmptyString == "") 18 | } 19 | } 20 | 21 | func BenchmarkCompareStringLen0(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | _boolResult = (len(_emptyString) == 0) 24 | _boolResult = (len(_notEmptyString) == 0) 25 | } 26 | } 27 | 28 | func BenchmarkCompareStringLenGreater0(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | _boolResult = (len(_emptyString) > 0) 31 | _boolResult = (len(_notEmptyString) > 0) 32 | } 33 | } 34 | 35 | func BenchmarkCompareStringLenNot0(b *testing.B) { 36 | for i := 0; i < b.N; i++ { 37 | _boolResult = (len(_emptyString) != 0) 38 | _boolResult = (len(_notEmptyString) != 0) 39 | } 40 | } 41 | 42 | func BenchmarkCompareStringNotEmpty(b *testing.B) { 43 | for i := 0; i < b.N; i++ { 44 | _boolResult = (_emptyString != "") 45 | _boolResult = (_notEmptyString != "") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /syscalls_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "strings" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func BenchmarkTimeNow(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | time.Now() 14 | } 15 | } 16 | 17 | func BenchmarkFunction(b *testing.B) { 18 | for i := 0; i < b.N; i++ { 19 | strings.HasPrefix("a", "asd") 20 | strings.HasPrefix("a", "asd") 21 | strings.HasPrefix("a", "asd") 22 | strings.HasPrefix("a", "asd") 23 | strings.HasPrefix("a", "asd") 24 | } 25 | } 26 | 27 | func BenchmarkPrintf(b *testing.B) { 28 | for i := 0; i < b.N; i++ { 29 | // Making this os.Stdout makes it take ~1us per op. 30 | fmt.Fprintf(ioutil.Discard, " ") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /uuid_arg_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | var _uuidData = [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} 6 | 7 | type uuidStr string 8 | type uuidArray [16]byte 9 | type uuidSlice []byte 10 | 11 | var ( 12 | _uuidStr uuidStr 13 | _uuidArray uuidArray 14 | _uuidSlice uuidSlice 15 | ) 16 | 17 | //go:noinline 18 | func useUUIDStr(u uuidStr) { 19 | _uuidStr = u 20 | } 21 | 22 | //go:noinline 23 | func useUUIDArray(u uuidArray) { 24 | _uuidArray = u 25 | } 26 | 27 | //go:noinline 28 | func useUUIDSlice(u uuidSlice) { 29 | _uuidSlice = u 30 | } 31 | 32 | func BenchmarkUseUUIDStr(b *testing.B) { 33 | u := uuidStr(_uuidData[:]) 34 | for i := 0; i < b.N; i++ { 35 | useUUIDStr(u) 36 | } 37 | } 38 | 39 | func BenchmarkUseUUIDSlice(b *testing.B) { 40 | u := uuidSlice(_uuidData[:]) 41 | for i := 0; i < b.N; i++ { 42 | useUUIDSlice(u) 43 | } 44 | } 45 | 46 | func BenchmarkUseUUIDArray(b *testing.B) { 47 | u := uuidArray(_uuidData) 48 | for i := 0; i < b.N; i++ { 49 | useUUIDArray(u) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /wgchan_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | func doWork() {} 9 | 10 | func BenchmarkSingleWaitGroup(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | var wg sync.WaitGroup 13 | wg.Add(1) 14 | 15 | go func() { 16 | defer wg.Done() 17 | doWork() 18 | }() 19 | 20 | wg.Wait() 21 | } 22 | } 23 | 24 | func BenchmarkSingleChanClose(b *testing.B) { 25 | for i := 0; i < b.N; i++ { 26 | ch := make(chan struct{}) 27 | go func() { 28 | defer close(ch) 29 | doWork() 30 | }() 31 | 32 | <-ch 33 | } 34 | } 35 | --------------------------------------------------------------------------------