Skip to content

Commit d628101

Browse files
joeybloggsjoeybloggs
authored andcommitted
minor perf improvements for more balanced encoder and decoder
``` benchmark old ns/op new ns/op delta BenchmarkSimpleUserDecodeStruct-8 318 336 +5.66% BenchmarkSimpleUserDecodeStructParallel-8 95.2 99.5 +4.52% BenchmarkSimpleUserEncodeStruct-8 1000 972 -2.80% BenchmarkSimpleUserEncodeStructParallel-8 325 329 +1.23% BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1058 1014 -4.16% BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 324 294 -9.26% BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 4823 4799 -0.50% BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1732 1581 -8.72% BenchmarkComplexArrayDecodeStructAllTypes-8 16340 16326 -0.09% BenchmarkComplexArrayDecodeStructAllTypesParallel-8 5105 4710 -7.74% BenchmarkComplexArrayEncodeStructAllTypes-8 16343 16303 -0.24% BenchmarkComplexArrayEncodeStructAllTypesParallel-8 5969 4979 -16.59% BenchmarkComplexMapDecodeStructAllTypes-8 21259 21998 +3.48% BenchmarkComplexMapDecodeStructAllTypesParallel-8 7493 6542 -12.69% BenchmarkComplexMapEncodeStructAllTypes-8 17060 17069 +0.05% BenchmarkComplexMapEncodeStructAllTypesParallel-8 6421 5609 -12.65% BenchmarkDecodeNestedStruct-8 3488 3366 -3.50% BenchmarkDecodeNestedStructParallel-8 1203 1096 -8.89% BenchmarkEncodeNestedStruct-8 2286 2230 -2.45% BenchmarkEncodeNestedStructParallel-8 939 780 -16.93% benchmark old allocs new allocs delta BenchmarkSimpleUserDecodeStruct-8 1 1 +0.00% BenchmarkSimpleUserDecodeStructParallel-8 1 1 +0.00% BenchmarkSimpleUserEncodeStruct-8 12 11 -8.33% BenchmarkSimpleUserEncodeStructParallel-8 12 11 -8.33% BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1 1 +0.00% BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 1 1 +0.00% BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 47 46 -2.13% BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 47 46 -2.13% BenchmarkComplexArrayDecodeStructAllTypes-8 122 121 -0.82% BenchmarkComplexArrayDecodeStructAllTypesParallel-8 122 121 -0.82% BenchmarkComplexArrayEncodeStructAllTypes-8 147 146 -0.68% BenchmarkComplexArrayEncodeStructAllTypesParallel-8 147 146 -0.68% BenchmarkComplexMapDecodeStructAllTypes-8 131 130 -0.76% BenchmarkComplexMapDecodeStructAllTypesParallel-8 131 130 -0.76% BenchmarkComplexMapEncodeStructAllTypes-8 176 175 -0.57% BenchmarkComplexMapEncodeStructAllTypesParallel-8 176 175 -0.57% BenchmarkDecodeNestedStruct-8 15 14 -6.67% BenchmarkDecodeNestedStructParallel-8 15 14 -6.67% BenchmarkEncodeNestedStruct-8 17 16 -5.88% BenchmarkEncodeNestedStructParallel-8 17 16 -5.88% benchmark old bytes new bytes delta BenchmarkSimpleUserDecodeStruct-8 64 64 +0.00% BenchmarkSimpleUserDecodeStructParallel-8 64 64 +0.00% BenchmarkSimpleUserEncodeStruct-8 549 485 -11.66% BenchmarkSimpleUserEncodeStructParallel-8 549 485 -11.66% BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 96 96 +0.00% BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 96 96 +0.00% BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 3073 3009 -2.08% BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 3072 3010 -2.02% BenchmarkComplexArrayDecodeStructAllTypes-8 2289 2257 -1.40% BenchmarkComplexArrayDecodeStructAllTypesParallel-8 2291 2257 -1.48% BenchmarkComplexArrayEncodeStructAllTypes-8 7351 7288 -0.86% BenchmarkComplexArrayEncodeStructAllTypesParallel-8 7351 7290 -0.83% BenchmarkComplexMapDecodeStructAllTypes-8 5338 5306 -0.60% BenchmarkComplexMapDecodeStructAllTypesParallel-8 5342 5308 -0.64% BenchmarkComplexMapEncodeStructAllTypes-8 7161 7100 -0.85% BenchmarkComplexMapEncodeStructAllTypesParallel-8 7161 7099 -0.87% BenchmarkDecodeNestedStruct-8 416 384 -7.69% BenchmarkDecodeNestedStructParallel-8 416 384 -7.69% BenchmarkEncodeNestedStruct-8 768 704 -8.33% BenchmarkEncodeNestedStructParallel-8 768 704 -8.33% ```
1 parent eb37b57 commit d628101

File tree

6 files changed

+97
-77
lines changed

6 files changed

+97
-77
lines changed

README.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package form
22
============
33
<img align="right" src="https://raw.githubusercontent.com/go-playground/form/master/logo.jpg">
4-
![Project status](https://img.shields.io/badge/version-2.0.0-green.svg)
4+
![Project status](https://img.shields.io/badge/version-2.1.0-green.svg)
55
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/form/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/form)
66
[![Coverage Status](https://coveralls.io/repos/github/go-playground/form/badge.svg?branch=master)](https://coveralls.io/github/go-playground/form?branch=master)
77
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/form)](https://goreportcard.com/report/github.com/go-playground/form)
@@ -270,26 +270,26 @@ NOTE: the 1 allocation and B/op in the first 4 decodes is actually the struct al
270270
go test -bench=. -benchmem=true
271271

272272
PASS
273-
BenchmarkSimpleUserDecodeStruct-8 5000000 318 ns/op 64 B/op 1 allocs/op
274-
BenchmarkSimpleUserDecodeStructParallel-8 20000000 95.2 ns/op 64 B/op 1 allocs/op
275-
BenchmarkSimpleUserEncodeStruct-8 1000000 1000 ns/op 549 B/op 12 allocs/op
276-
BenchmarkSimpleUserEncodeStructParallel-8 5000000 325 ns/op 549 B/op 12 allocs/op
277-
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1000000 1058 ns/op 96 B/op 1 allocs/op
278-
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 324 ns/op 96 B/op 1 allocs/op
279-
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4823 ns/op 3073 B/op 47 allocs/op
280-
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1732 ns/op 3072 B/op 47 allocs/op
281-
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 16340 ns/op 2289 B/op 122 allocs/op
282-
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 300000 5105 ns/op 2291 B/op 122 allocs/op
283-
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 16343 ns/op 7351 B/op 147 allocs/op
284-
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 5969 ns/op 7351 B/op 147 allocs/op
285-
BenchmarkComplexMapDecodeStructAllTypes-8 100000 21259 ns/op 5338 B/op 131 allocs/op
286-
BenchmarkComplexMapDecodeStructAllTypesParallel-8 200000 7493 ns/op 5342 B/op 131 allocs/op
287-
BenchmarkComplexMapEncodeStructAllTypes-8 100000 17060 ns/op 7161 B/op 176 allocs/op
288-
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 6421 ns/op 7161 B/op 176 allocs/op
289-
BenchmarkDecodeNestedStruct-8 300000 3488 ns/op 416 B/op 15 allocs/op
290-
BenchmarkDecodeNestedStructParallel-8 1000000 1203 ns/op 416 B/op 15 allocs/op
291-
BenchmarkEncodeNestedStruct-8 1000000 2286 ns/op 768 B/op 17 allocs/op
292-
BenchmarkEncodeNestedStructParallel-8 2000000 939 ns/op 768 B/op 17 allocs/op
273+
BenchmarkSimpleUserDecodeStruct-8 5000000 336 ns/op 64 B/op 1 allocs/op
274+
BenchmarkSimpleUserDecodeStructParallel-8 20000000 99.5 ns/op 64 B/op 1 allocs/op
275+
BenchmarkSimpleUserEncodeStruct-8 2000000 972 ns/op 485 B/op 11 allocs/op
276+
BenchmarkSimpleUserEncodeStructParallel-8 5000000 329 ns/op 485 B/op 11 allocs/op
277+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1000000 1014 ns/op 96 B/op 1 allocs/op
278+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 294 ns/op 96 B/op 1 allocs/op
279+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4799 ns/op 3009 B/op 46 allocs/op
280+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1581 ns/op 3010 B/op 46 allocs/op
281+
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 16326 ns/op 2257 B/op 121 allocs/op
282+
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 300000 4710 ns/op 2257 B/op 121 allocs/op
283+
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 16303 ns/op 7288 B/op 146 allocs/op
284+
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 4979 ns/op 7290 B/op 146 allocs/op
285+
BenchmarkComplexMapDecodeStructAllTypes-8 100000 21998 ns/op 5306 B/op 130 allocs/op
286+
BenchmarkComplexMapDecodeStructAllTypesParallel-8 200000 6542 ns/op 5308 B/op 130 allocs/op
287+
BenchmarkComplexMapEncodeStructAllTypes-8 100000 17069 ns/op 7100 B/op 175 allocs/op
288+
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 5609 ns/op 7099 B/op 175 allocs/op
289+
BenchmarkDecodeNestedStruct-8 500000 3366 ns/op 384 B/op 14 allocs/op
290+
BenchmarkDecodeNestedStructParallel-8 2000000 1096 ns/op 384 B/op 14 allocs/op
291+
BenchmarkEncodeNestedStruct-8 1000000 2230 ns/op 704 B/op 16 allocs/op
292+
BenchmarkEncodeNestedStructParallel-8 2000000 780 ns/op 704 B/op 16 allocs/op
293293
```
294294

295295
Competitor benchmarks can be found [here](https://github.com/go-playground/form/blob/master/benchmarks/benchmarks.md)

benchmarks/benchmarks.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
## Benchmarks
22

3-
Last Run July 26, 2016
3+
Competitor Benchmarks Last Run July 26, 2016
44

55
### go-playground/form
66
```go
77
PASS
8-
BenchmarkSimpleUserDecodeStruct-8 5000000 318 ns/op 64 B/op 1 allocs/op
9-
BenchmarkSimpleUserDecodeStructParallel-8 20000000 95.2 ns/op 64 B/op 1 allocs/op
10-
BenchmarkSimpleUserEncodeStruct-8 1000000 1000 ns/op 549 B/op 12 allocs/op
11-
BenchmarkSimpleUserEncodeStructParallel-8 5000000 325 ns/op 549 B/op 12 allocs/op
12-
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1000000 1058 ns/op 96 B/op 1 allocs/op
13-
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 324 ns/op 96 B/op 1 allocs/op
14-
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4823 ns/op 3073 B/op 47 allocs/op
15-
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1732 ns/op 3072 B/op 47 allocs/op
16-
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 16340 ns/op 2289 B/op 122 allocs/op
17-
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 300000 5105 ns/op 2291 B/op 122 allocs/op
18-
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 16343 ns/op 7351 B/op 147 allocs/op
19-
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 5969 ns/op 7351 B/op 147 allocs/op
20-
BenchmarkComplexMapDecodeStructAllTypes-8 100000 21259 ns/op 5338 B/op 131 allocs/op
21-
BenchmarkComplexMapDecodeStructAllTypesParallel-8 200000 7493 ns/op 5342 B/op 131 allocs/op
22-
BenchmarkComplexMapEncodeStructAllTypes-8 100000 17060 ns/op 7161 B/op 176 allocs/op
23-
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 6421 ns/op 7161 B/op 176 allocs/op
24-
BenchmarkDecodeNestedStruct-8 300000 3488 ns/op 416 B/op 15 allocs/op
25-
BenchmarkDecodeNestedStructParallel-8 1000000 1203 ns/op 416 B/op 15 allocs/op
26-
BenchmarkEncodeNestedStruct-8 1000000 2286 ns/op 768 B/op 17 allocs/op
27-
BenchmarkEncodeNestedStructParallel-8 2000000 939 ns/op 768 B/op 17 allocs/op
8+
BenchmarkSimpleUserDecodeStruct-8 5000000 336 ns/op 64 B/op 1 allocs/op
9+
BenchmarkSimpleUserDecodeStructParallel-8 20000000 99.5 ns/op 64 B/op 1 allocs/op
10+
BenchmarkSimpleUserEncodeStruct-8 2000000 972 ns/op 485 B/op 11 allocs/op
11+
BenchmarkSimpleUserEncodeStructParallel-8 5000000 329 ns/op 485 B/op 11 allocs/op
12+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8 1000000 1014 ns/op 96 B/op 1 allocs/op
13+
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8 5000000 294 ns/op 96 B/op 1 allocs/op
14+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8 300000 4799 ns/op 3009 B/op 46 allocs/op
15+
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8 1000000 1581 ns/op 3010 B/op 46 allocs/op
16+
BenchmarkComplexArrayDecodeStructAllTypes-8 100000 16326 ns/op 2257 B/op 121 allocs/op
17+
BenchmarkComplexArrayDecodeStructAllTypesParallel-8 300000 4710 ns/op 2257 B/op 121 allocs/op
18+
BenchmarkComplexArrayEncodeStructAllTypes-8 100000 16303 ns/op 7288 B/op 146 allocs/op
19+
BenchmarkComplexArrayEncodeStructAllTypesParallel-8 300000 4979 ns/op 7290 B/op 146 allocs/op
20+
BenchmarkComplexMapDecodeStructAllTypes-8 100000 21998 ns/op 5306 B/op 130 allocs/op
21+
BenchmarkComplexMapDecodeStructAllTypesParallel-8 200000 6542 ns/op 5308 B/op 130 allocs/op
22+
BenchmarkComplexMapEncodeStructAllTypes-8 100000 17069 ns/op 7100 B/op 175 allocs/op
23+
BenchmarkComplexMapEncodeStructAllTypesParallel-8 300000 5609 ns/op 7099 B/op 175 allocs/op
24+
BenchmarkDecodeNestedStruct-8 500000 3366 ns/op 384 B/op 14 allocs/op
25+
BenchmarkDecodeNestedStructParallel-8 2000000 1096 ns/op 384 B/op 14 allocs/op
26+
BenchmarkEncodeNestedStruct-8 1000000 2230 ns/op 704 B/op 16 allocs/op
27+
BenchmarkEncodeNestedStructParallel-8 2000000 780 ns/op 704 B/op 16 allocs/op
2828
```
2929

3030
### gorilla/schema

decoder.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type decoder struct {
2121
dm dataMap
2222
values url.Values
2323
maxKeyLen int
24+
namespace []byte
2425
}
2526

2627
func (d *decoder) setError(namespace []byte, err error) {
@@ -46,11 +47,13 @@ func (d *decoder) findAlias(ns string) *recursiveData {
4647
func (d *decoder) parseMapData() {
4748

4849
// already parsed
49-
if len(d.dm) != 0 {
50+
if len(d.dm) > 0 {
5051
return
5152
}
5253

53-
d.dm = d.d.dataPool.Get().(dataMap)[0:0]
54+
d.maxKeyLen = 0
55+
d.dm = d.dm[0:0]
56+
5457
var i int
5558
var idx int
5659
var l int

encoder.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99
)
1010

1111
type encoder struct {
12-
e *Encoder
13-
errs EncodeErrors
14-
values url.Values
12+
e *Encoder
13+
errs EncodeErrors
14+
values url.Values
15+
namespace []byte
1516
}
1617

1718
func (e *encoder) setError(namespace []byte, err error) {

form_decoder.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,20 @@ type Decoder struct {
7373
// NewDecoder creates a new decoder instance with sane defaults
7474
func NewDecoder() *Decoder {
7575

76-
return &Decoder{
76+
d := &Decoder{
7777
tagName: "form",
7878
structCache: newStructCacheMap(),
7979
maxArraySize: 10000,
80-
dataPool: &sync.Pool{New: func() interface{} {
81-
return make(dataMap, 0, 0)
82-
}},
8380
}
81+
82+
d.dataPool = &sync.Pool{New: func() interface{} {
83+
return &decoder{
84+
d: d,
85+
namespace: make([]byte, 0, 64),
86+
}
87+
}}
88+
89+
return d
8490
}
8591

8692
// SetTagName sets the given tag name to be used by the decoder.
@@ -116,35 +122,31 @@ func (d *Decoder) RegisterCustomTypeFunc(fn DecodeCustomTypeFunc, types ...inter
116122
// Decode returns an InvalidDecoderError if interface passed is invalid.
117123
func (d *Decoder) Decode(v interface{}, values url.Values) (err error) {
118124

119-
dec := &decoder{
120-
d: d,
121-
values: values,
122-
}
123-
124125
val := reflect.ValueOf(v)
125126

126127
if val.Kind() != reflect.Ptr || val.IsNil() {
127128
return &InvalidDecoderError{reflect.TypeOf(v)}
128129
}
129130

131+
dec := d.dataPool.Get().(*decoder)
132+
dec.values = values
133+
dec.dm = dec.dm[0:0]
134+
130135
val = val.Elem()
131136
typ := val.Type()
132137

133138
if val.Kind() == reflect.Struct && typ != timeType {
134-
dec.traverseStruct(val, typ, make([]byte, 0, 64))
139+
dec.traverseStruct(val, typ, dec.namespace[0:0])
135140
} else {
136-
dec.setFieldByType(val, make([]byte, 0, 64), 0)
137-
}
138-
139-
if len(dec.dm) > 0 {
140-
d.dataPool.Put(dec.dm)
141+
dec.setFieldByType(val, dec.namespace[0:0], 0)
141142
}
142143

143-
if len(dec.errs) == 0 {
144-
return nil
144+
if len(dec.errs) > 0 {
145+
err = dec.errs
146+
dec.errs = nil
145147
}
146148

147-
err = dec.errs
149+
d.dataPool.Put(dec)
148150

149151
return
150152
}

form_encoder.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/url"
66
"reflect"
77
"strings"
8+
"sync"
89
)
910

1011
// EncodeCustomTypeFunc allows for registering/overriding types to be parsed.
@@ -46,15 +47,25 @@ type Encoder struct {
4647
tagName string
4748
structCache *structCacheMap
4849
customTypeFuncs map[reflect.Type]EncodeCustomTypeFunc
50+
dataPool *sync.Pool
4951
}
5052

5153
// NewEncoder creates a new encoder instance with sane defaults
5254
func NewEncoder() *Encoder {
5355

54-
return &Encoder{
56+
e := &Encoder{
5557
tagName: "form",
5658
structCache: newStructCacheMap(),
5759
}
60+
61+
e.dataPool = &sync.Pool{New: func() interface{} {
62+
return &encoder{
63+
e: e,
64+
namespace: make([]byte, 0, 64),
65+
}
66+
}}
67+
68+
return e
5869
}
5970

6071
// SetTagName sets the given tag name to be used by the decoder.
@@ -77,28 +88,31 @@ func (e *Encoder) RegisterCustomTypeFunc(fn EncodeCustomTypeFunc, types ...inter
7788
}
7889

7990
// Encode encodes the given values and sets the corresponding struct values
80-
func (e *Encoder) Encode(v interface{}) (url.Values, error) {
81-
82-
enc := &encoder{
83-
e: e,
84-
values: make(url.Values),
85-
}
91+
func (e *Encoder) Encode(v interface{}) (values url.Values, err error) {
8692

8793
val, kind := ExtractType(reflect.ValueOf(v))
8894

8995
if kind == reflect.Ptr || kind == reflect.Interface || kind == reflect.Invalid {
9096
return nil, &InvalidEncodeError{reflect.TypeOf(v)}
9197
}
9298

99+
enc := e.dataPool.Get().(*encoder)
100+
enc.values = make(url.Values)
101+
93102
if kind == reflect.Struct && val.Type() != timeType {
94-
enc.traverseStruct(val, make([]byte, 0, 64), -1)
103+
enc.traverseStruct(val, enc.namespace[0:0], -1)
95104
} else {
96-
enc.setFieldByType(val, make([]byte, 0, 64), -1)
105+
enc.setFieldByType(val, enc.namespace[0:0], -1)
97106
}
98107

99-
if len(enc.errs) == 0 {
100-
return enc.values, nil
108+
if len(enc.errs) > 0 {
109+
err = enc.errs
110+
enc.errs = nil
101111
}
102112

103-
return enc.values, enc.errs
113+
values = enc.values
114+
115+
e.dataPool.Put(enc)
116+
117+
return
104118
}

0 commit comments

Comments
 (0)