150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package builder
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"math/rand"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| 
 | |
| 	"google.golang.org/protobuf/proto"
 | |
| 
 | |
| 	pb "go.unistack.org/micro-client-http/v3/builder/proto"
 | |
| )
 | |
| 
 | |
| // sink prevents the compiler from optimizing away parsePathTemplate results.
 | |
| var sink *pathTemplate
 | |
| 
 | |
| func BenchmarkParsePathTemplate(b *testing.B) {
 | |
| 	r := rand.New(rand.NewSource(1))
 | |
| 
 | |
| 	benchInput := func(size int) string {
 | |
| 		sb := strings.Builder{}
 | |
| 		sb.Grow(size * 10)
 | |
| 
 | |
| 		for i := 0; i < size; i++ {
 | |
| 			name := fmt.Sprintf("var%d", r.Intn(1000))
 | |
| 
 | |
| 			if r.Intn(5) == 0 {
 | |
| 				sb.WriteString(fmt.Sprintf("{%s=**}", name))
 | |
| 			} else {
 | |
| 				sb.WriteString(fmt.Sprintf("{%s}", name))
 | |
| 			}
 | |
| 		}
 | |
| 		return sb.String()
 | |
| 	}
 | |
| 
 | |
| 	sizes := []int{1_000, 10_000, 50_000, 100_000}
 | |
| 	for _, size := range sizes {
 | |
| 		input := benchInput(size)
 | |
| 		b.Run(fmt.Sprintf("N=%d", size), func(b *testing.B) {
 | |
| 			b.ReportAllocs()
 | |
| 			for i := 0; i < b.N; i++ {
 | |
| 				var err error
 | |
| 				sink, err = parsePathTemplate(input)
 | |
| 				if err != nil && testing.Verbose() {
 | |
| 					b.Fatal(err)
 | |
| 				}
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func BenchmarkRequestBuilder(b *testing.B) {
 | |
| 	r := rand.New(rand.NewSource(time.Now().UnixNano()))
 | |
| 
 | |
| 	makeMsg := func(fieldCount int) proto.Message {
 | |
| 		switch fieldCount {
 | |
| 		case 5:
 | |
| 			return &pb.Benchmark_Case5{
 | |
| 				Field1: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field2: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field3: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field4: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field5: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 			}
 | |
| 		case 10:
 | |
| 			return &pb.Benchmark_Case10{
 | |
| 				Field1:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field2:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field3:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field4:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field5:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field6:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field7:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field8:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field9:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field10: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 			}
 | |
| 		case 30:
 | |
| 			return &pb.Benchmark_Case30{
 | |
| 				Field1:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field2:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field3:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field4:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field5:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field6:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field7:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field8:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field9:  fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field10: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field11: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field12: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field13: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field14: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field15: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field16: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field17: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field18: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field19: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field20: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field21: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field22: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field23: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field24: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field25: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field26: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field27: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field28: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field29: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 				Field30: fmt.Sprintf("value%d", r.Intn(1000)),
 | |
| 			}
 | |
| 		default:
 | |
| 			b.Fatal("undefined field count")
 | |
| 			return nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tests := []struct {
 | |
| 		name       string
 | |
| 		pathTmpl   string
 | |
| 		bodyOption string
 | |
| 	}{
 | |
| 		{"all fields in path", "/resource/{field1}/{field2}", ""},
 | |
| 		{"single field body", "/resource/{field1}", "field4"},
 | |
| 		{"full body", "/resource", "*"},
 | |
| 	}
 | |
| 
 | |
| 	for _, fields := range []int{5, 10, 30} {
 | |
| 		for _, tt := range tests {
 | |
| 			b.Run(fmt.Sprintf("%s_%d_fields", tt.name, fields), func(b *testing.B) {
 | |
| 				b.ReportAllocs()
 | |
| 				b.ResetTimer()
 | |
| 
 | |
| 				for i := 0; i < b.N; i++ {
 | |
| 					msg := makeMsg(fields)
 | |
| 					rb, err := NewRequestBuilder(tt.pathTmpl, "POST", tt.bodyOption, msg)
 | |
| 					if err != nil {
 | |
| 						b.Fatalf("new request builder: %v", err)
 | |
| 					}
 | |
| 
 | |
| 					_, _, err = rb.Build()
 | |
| 					if err != nil {
 | |
| 						b.Fatalf("build: %v", err)
 | |
| 					}
 | |
| 				}
 | |
| 			})
 | |
| 		}
 | |
| 	}
 | |
| }
 |