package benchmark import ( "bytes" "encoding/json" "fmt" "reflect" "testing" gojson "github.com/goccy/go-json" ) // Benchmark decoding from a slow io.Reader that never fills the buffer completely func Benchmark_Decode_SlowReader_EncodingJson(b *testing.B) { var expected LargePayload if err := json.Unmarshal(LargeFixture, &expected); err != nil { b.Fatal(err) } for _, chunkSize := range [5]int{16384, 4096, 1024, 256, 64} { b.Run(fmt.Sprintf("chunksize %v", chunkSize), func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { index = 0 var got LargePayload if err := json.NewDecoder(slowReader{chunkSize: chunkSize}).Decode(&got); err != nil { b.Fatal(err) } if !reflect.DeepEqual(expected, got) { b.Fatalf("failed to decode. expected:[%+v] but got:[%+v]", expected, got) } } }) } } func Benchmark_Decode_SlowReader_GoJson(b *testing.B) { var expected LargePayload if err := json.Unmarshal(LargeFixture, &expected); err != nil { b.Fatal(err) } for _, chunkSize := range []int{16384, 4096, 1024, 256, 64} { b.Run(fmt.Sprintf("chunksize %v", chunkSize), func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { index = 0 var got LargePayload if err := gojson.NewDecoder(slowReader{chunkSize: chunkSize}).Decode(&got); err != nil { b.Fatal(err) } if !reflect.DeepEqual(expected, got) { b.Fatalf("failed to decode. expected:[%+v] but got:[%+v]", expected, got) } } }) } } type slowReader struct { chunkSize int } var index int func (s slowReader) Read(p []byte) (n int, err error) { smallBuf := make([]byte, Min(s.chunkSize, len(p))) x := bytes.NewReader(LargeFixture) n, err = x.ReadAt(smallBuf, int64(index)) index += n copy(p, smallBuf) return } func Min(x, y int) int { if x < y { return x } return y }