gojay

high performance JSON encoder/decoder with stream API for Golang
git clone git://git.lair.cx/gojay
Log | Files | Refs | README | LICENSE

commit 8bc8707323078cfe8b83dd28f876aedf7a234f37
parent b0f9d289cb2739b2aea041d8ec614f791748c593
Author: francoispqt <francois@parquet.ninja>
Date:   Sun, 20 May 2018 20:16:36 +0800

add http-benchmarks example

Diffstat:
Aexamples/http-benchmarks/Makefile | 5+++++
Aexamples/http-benchmarks/README.md | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/http-benchmarks/gojay/main.go | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/http-benchmarks/post.lua | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/http-benchmarks/standard/main.go | 42++++++++++++++++++++++++++++++++++++++++++
5 files changed, 478 insertions(+), 0 deletions(-)

diff --git a/examples/http-benchmarks/Makefile b/examples/http-benchmarks/Makefile @@ -0,0 +1,4 @@ + +.PHONY: bench +bench: + wrk -d 20s -s post.lua http://localhost:3000 +\ No newline at end of file diff --git a/examples/http-benchmarks/README.md b/examples/http-benchmarks/README.md @@ -0,0 +1,52 @@ +# HTTP BENCHMARKS + +This package has two different implementation of a basic HTTP server in Go. It just takes a JSON body, unmarshals it and marshals it back to the response. + +It required `wrk` benchmarking tool, which you can find here: https://github.com/wg/wrk + +## How to run + +### gojay +```bash +cd /path/to/package && go run gojay/main.go +``` +Then run: +```bash +cd /path/to/package && make bench +``` + +### standard package (encoding/json) +```bash +cd /path/to/package && go run standard/main.go +``` +Then run: +```bash +cd /path/to/package && make bench +``` + +## Results + +Results presented here are ran on a MacBook Pro Mid 2015 2,2 GHz Intel Core i7 with 16G of RAM + +**gojay results:** +``` +Running 20s test @ http://localhost:3000 + 2 threads and 10 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 298.77us 341.40us 10.52ms 94.13% + Req/Sec 18.88k 1.89k 21.40k 73.63% + 755246 requests in 20.10s, 1.67GB read +Requests/sec: 37573.84 +Transfer/sec: 84.85MB +``` +**standard results:** +``` +Running 20s test @ http://localhost:3000 + 2 threads and 10 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 613.21us 557.50us 12.65ms 93.88% + Req/Sec 9.18k 423.20 10.10k 80.50% + 365404 requests in 20.00s, 811.60MB read +Requests/sec: 18269.66 +Transfer/sec: 40.58MB +``` +\ No newline at end of file diff --git a/examples/http-benchmarks/gojay/main.go b/examples/http-benchmarks/gojay/main.go @@ -0,0 +1,158 @@ +package main + +import ( + "log" + "net/http" + + "github.com/francoispqt/gojay" +) + +func main() { + log.Println("Listening on port 3000") + log.Fatal(http.ListenAndServe(":3000", http.HandlerFunc(handler))) +} + +func handler(w http.ResponseWriter, r *http.Request) { + var body Body + dec := gojay.BorrowDecoder(r.Body) + defer dec.Release() + err := dec.Decode(&body) + if err != nil { + panic(err) + } + w.Header().Set("Content-Type", "application/json") + enc := gojay.BorrowEncoder(w) + defer enc.Release() + err = enc.Encode(&body) + if err != nil { + panic(err) + } +} + +type Body struct { + Colors *colors `json:"colors"` +} + +func (c *Body) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + switch k { + case "colors": + cols := make(colors, 0) + c.Colors = &cols + return dec.Array(c.Colors) + } + return nil +} +func (b *Body) NKeys() int { + return 1 +} + +func (b *Body) MarshalJSONObject(enc *gojay.Encoder) { + enc.ArrayKey("colors", b.Colors) +} +func (b *Body) IsNil() bool { + return b == nil +} + +type colors []*Color + +func (b *colors) UnmarshalJSONArray(dec *gojay.Decoder) error { + color := &Color{} + if err := dec.Object(color); err != nil { + return err + } + *b = append(*b, color) + return nil +} + +func (b *colors) MarshalJSONArray(enc *gojay.Encoder) { + for _, color := range *b { + enc.Object(color) + } +} + +func (b *colors) IsNil() bool { + return len(*b) == 0 +} + +type Color struct { + Color string `json:"color,omitempty"` + Category string `json:"category,omitempty"` + Type string `json:"type,omitempty"` + Code *Code `json:"code,omitempty"` +} + +func (b *Color) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + switch k { + case "color": + return dec.String(&b.Color) + case "category": + return dec.String(&b.Category) + case "type": + return dec.String(&b.Type) + case "code": + b.Code = &Code{} + return dec.Object(b.Code) + } + return nil +} +func (b *Color) NKeys() int { + return 4 +} + +func (b *Color) MarshalJSONObject(enc *gojay.Encoder) { + enc.ObjectKey("code", b.Code) + enc.StringKey("color", b.Color) + enc.StringKey("category", b.Category) + enc.StringKey("type", b.Type) +} +func (b *Color) IsNil() bool { + return b == nil +} + +type Code struct { + RGBA *ints `json:"rgba,omitempty"` + Hex string `json:"hex,omitempty"` +} + +func (c *Code) UnmarshalJSONObject(dec *gojay.Decoder, k string) error { + switch k { + case "rgba": + rgba := make(ints, 0) + c.RGBA = &rgba + return dec.Array(&rgba) + case "hex": + return dec.String(&c.Hex) + } + return nil +} +func (b *Code) NKeys() int { + return 2 +} + +func (b *Code) MarshalJSONObject(enc *gojay.Encoder) { + enc.ArrayKey("rgba", b.RGBA) + enc.StringKey("hex", b.Hex) +} +func (b *Code) IsNil() bool { + return b == nil +} + +type ints []int + +func (v *ints) UnmarshalJSONArray(dec *gojay.Decoder) error { + var i int + if err := dec.Int(&i); err != nil { + return err + } + *v = append(*v, i) + return nil +} + +func (v *ints) MarshalJSONArray(enc *gojay.Encoder) { + for _, i := range *v { + enc.Int(i) + } +} +func (v *ints) IsNil() bool { + return v == nil || len(*v) == 0 +} diff --git a/examples/http-benchmarks/post.lua b/examples/http-benchmarks/post.lua @@ -0,0 +1,220 @@ +wrk.method = "POST" +wrk.body = [=[ + { + "colors": [ + { + "color": "black", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,255,1], + "hex": "#000" + } + }, + { + "color": "white", + "category": "value", + "code": { + "rgba": [0,0,0,1], + "hex": "#FFF" + } + }, + { + "color": "red", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,0,0,1], + "hex": "#FF0" + } + }, + { + "color": "blue", + "category": "hue", + "type": "primary", + "code": { + "rgba": [0,0,255,1], + "hex": "#00F" + } + }, + { + "color": "yellow", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,0,1], + "hex": "#FF0" + } + }, + { + "color": "green", + "category": "hue", + "type": "secondary", + "code": { + "rgba": [0,255,0,1], + "hex": "#0F0" + } + }, + { + "color": "black", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,255,1], + "hex": "#000" + } + }, + { + "color": "white", + "category": "value", + "code": { + "rgba": [0,0,0,1], + "hex": "#FFF" + } + }, + { + "color": "red", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,0,0,1], + "hex": "#FF0" + } + }, + { + "color": "blue", + "category": "hue", + "type": "primary", + "code": { + "rgba": [0,0,255,1], + "hex": "#00F" + } + }, + { + "color": "yellow", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,0,1], + "hex": "#FF0" + } + }, + { + "color": "green", + "category": "hue", + "type": "secondary", + "code": { + "rgba": [0,255,0,1], + "hex": "#0F0" + } + }, + { + "color": "black", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,255,1], + "hex": "#000" + } + }, + { + "color": "white", + "category": "value", + "code": { + "rgba": [0,0,0,1], + "hex": "#FFF" + } + }, + { + "color": "red", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,0,0,1], + "hex": "#FF0" + } + }, + { + "color": "blue", + "category": "hue", + "type": "primary", + "code": { + "rgba": [0,0,255,1], + "hex": "#00F" + } + }, + { + "color": "yellow", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,0,1], + "hex": "#FF0" + } + }, + { + "color": "green", + "category": "hue", + "type": "secondary", + "code": { + "rgba": [0,255,0,1], + "hex": "#0F0" + } + }, + { + "color": "black", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,255,1], + "hex": "#000" + } + }, + { + "color": "white", + "category": "value", + "code": { + "rgba": [0,0,0,1], + "hex": "#FFF" + } + }, + { + "color": "red", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,0,0,1], + "hex": "#FF0" + } + }, + { + "color": "blue", + "category": "hue", + "type": "primary", + "code": { + "rgba": [0,0,255,1], + "hex": "#00F" + } + }, + { + "color": "yellow", + "category": "hue", + "type": "primary", + "code": { + "rgba": [255,255,0,1], + "hex": "#FF0" + } + }, + { + "color": "green", + "category": "hue", + "type": "secondary", + "code": { + "rgba": [0,255,0,1], + "hex": "#0F0" + } + } + ] + } +]=] +wrk.headers["Content-Type"] = "application/json" diff --git a/examples/http-benchmarks/standard/main.go b/examples/http-benchmarks/standard/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" +) + +func main() { + log.Println("Listening on port 3000") + log.Fatal(http.ListenAndServe(":3000", http.HandlerFunc(handler))) +} + +func handler(w http.ResponseWriter, r *http.Request) { + var body Body + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + panic(err) + } + + w.Header().Set("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(body) + if err != nil { + panic(err) + } +} + +type Body struct { + Colors []Color `json:"colors"` +} + +type Color struct { + Color string `json:"color,omitempty"` + Category string `json:"category,omitempty"` + Type string `json:"type,omitempty"` + Code Code `json:"code,omitempty"` +} + +type Code struct { + RGBA []int `json:"rgba,omitempty"` + Hex string `json:"hex,omitempty"` +}