1// Copyright 2017 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package spanner 16 17import ( 18 "reflect" 19 "strconv" 20 "testing" 21 22 "cloud.google.com/go/civil" 23 proto3 "github.com/golang/protobuf/ptypes/struct" 24 sppb "google.golang.org/genproto/googleapis/spanner/v1" 25) 26 27func BenchmarkEncodeIntArray(b *testing.B) { 28 for _, s := range []struct { 29 name string 30 f func(a []int) (*proto3.Value, *sppb.Type, error) 31 }{ 32 {"Orig", encodeIntArrayOrig}, 33 {"Func", encodeIntArrayFunc}, 34 {"Reflect", encodeIntArrayReflect}, 35 } { 36 b.Run(s.name, func(b *testing.B) { 37 for _, size := range []int{1, 10, 100, 1000} { 38 a := make([]int, size) 39 b.Run(strconv.Itoa(size), func(b *testing.B) { 40 for i := 0; i < b.N; i++ { 41 s.f(a) 42 } 43 }) 44 } 45 }) 46 } 47} 48 49func encodeIntArrayOrig(a []int) (*proto3.Value, *sppb.Type, error) { 50 vs := make([]*proto3.Value, len(a)) 51 var err error 52 for i := range a { 53 vs[i], _, err = encodeValue(a[i]) 54 if err != nil { 55 return nil, nil, err 56 } 57 } 58 return listProto(vs...), listType(intType()), nil 59} 60 61func encodeIntArrayFunc(a []int) (*proto3.Value, *sppb.Type, error) { 62 v, err := encodeArray(len(a), func(i int) interface{} { return a[i] }) 63 if err != nil { 64 return nil, nil, err 65 } 66 return v, listType(intType()), nil 67} 68 69func encodeIntArrayReflect(a []int) (*proto3.Value, *sppb.Type, error) { 70 v, err := encodeArrayReflect(a) 71 if err != nil { 72 return nil, nil, err 73 } 74 return v, listType(intType()), nil 75} 76 77func encodeArrayReflect(a interface{}) (*proto3.Value, error) { 78 va := reflect.ValueOf(a) 79 len := va.Len() 80 vs := make([]*proto3.Value, len) 81 var err error 82 for i := 0; i < len; i++ { 83 vs[i], _, err = encodeValue(va.Index(i).Interface()) 84 if err != nil { 85 return nil, err 86 } 87 } 88 return listProto(vs...), nil 89} 90 91func BenchmarkDecodeGeneric(b *testing.B) { 92 v := stringProto("test") 93 t := stringType() 94 var g GenericColumnValue 95 b.ResetTimer() 96 for i := 0; i < b.N; i++ { 97 decodeValue(v, t, &g) 98 } 99} 100 101func BenchmarkDecodeString(b *testing.B) { 102 v := stringProto("test") 103 t := stringType() 104 var s string 105 b.ResetTimer() 106 for i := 0; i < b.N; i++ { 107 decodeValue(v, t, &s) 108 } 109} 110 111func BenchmarkDecodeCustomString(b *testing.B) { 112 v := stringProto("test") 113 t := stringType() 114 type CustomString string 115 var s CustomString 116 b.ResetTimer() 117 for i := 0; i < b.N; i++ { 118 decodeValue(v, t, &s) 119 } 120} 121 122func BenchmarkDecodeArray(b *testing.B) { 123 for _, size := range []int{1, 10, 100, 1000} { 124 vals := make([]*proto3.Value, size) 125 for i := 0; i < size; i++ { 126 vals[i] = dateProto(d1) 127 } 128 lv := &proto3.ListValue{Values: vals} 129 b.Run(strconv.Itoa(size), func(b *testing.B) { 130 for _, s := range []struct { 131 name string 132 decode func(*proto3.ListValue) 133 }{ 134 {"DateDirect", decodeArrayDateDirect}, 135 {"DateFunc", decodeArrayDateFunc}, 136 {"DateReflect", decodeArrayDateReflect}, 137 {"StringDecodeStringArray", decodeStringArrayWrap}, 138 {"StringDirect", decodeArrayStringDirect}, 139 {"StringFunc", decodeArrayStringFunc}, 140 {"StringReflect", decodeArrayStringReflect}, 141 } { 142 b.Run(s.name, func(b *testing.B) { 143 for i := 0; i < b.N; i++ { 144 s.decode(lv) 145 } 146 }) 147 } 148 }) 149 150 } 151} 152 153func decodeArrayDateDirect(pb *proto3.ListValue) { 154 a := make([]civil.Date, len(pb.Values)) 155 t := dateType() 156 for i, v := range pb.Values { 157 if err := decodeValue(v, t, &a[i]); err != nil { 158 panic(err) 159 } 160 } 161} 162 163func decodeArrayDateFunc(pb *proto3.ListValue) { 164 a := make([]civil.Date, len(pb.Values)) 165 if err := decodeArrayFunc(pb, "DATE", dateType(), func(i int) interface{} { return &a[i] }); err != nil { 166 panic(err) 167 } 168} 169 170func decodeArrayDateReflect(pb *proto3.ListValue) { 171 var a []civil.Date 172 if err := decodeArrayReflect(pb, "DATE", dateType(), &a); err != nil { 173 panic(err) 174 } 175} 176 177func decodeStringArrayWrap(pb *proto3.ListValue) { 178 if _, err := decodeStringArray(pb); err != nil { 179 panic(err) 180 } 181} 182 183func decodeArrayStringDirect(pb *proto3.ListValue) { 184 a := make([]string, len(pb.Values)) 185 t := stringType() 186 for i, v := range pb.Values { 187 if err := decodeValue(v, t, &a[i]); err != nil { 188 panic(err) 189 } 190 } 191} 192 193func decodeArrayStringFunc(pb *proto3.ListValue) { 194 a := make([]string, len(pb.Values)) 195 if err := decodeArrayFunc(pb, "STRING", stringType(), func(i int) interface{} { return &a[i] }); err != nil { 196 panic(err) 197 } 198} 199 200func decodeArrayStringReflect(pb *proto3.ListValue) { 201 var a []string 202 if err := decodeArrayReflect(pb, "STRING", stringType(), &a); err != nil { 203 panic(err) 204 } 205} 206 207func decodeArrayFunc(pb *proto3.ListValue, name string, typ *sppb.Type, elptr func(int) interface{}) error { 208 if pb == nil { 209 return errNilListValue(name) 210 } 211 for i, v := range pb.Values { 212 if err := decodeValue(v, typ, elptr(i)); err != nil { 213 return errDecodeArrayElement(i, v, name, err) 214 } 215 } 216 return nil 217} 218 219func decodeArrayReflect(pb *proto3.ListValue, name string, typ *sppb.Type, aptr interface{}) error { 220 if pb == nil { 221 return errNilListValue(name) 222 } 223 av := reflect.ValueOf(aptr).Elem() 224 av.Set(reflect.MakeSlice(av.Type(), len(pb.Values), len(pb.Values))) 225 for i, v := range pb.Values { 226 if err := decodeValue(v, typ, av.Index(i).Addr().Interface()); err != nil { 227 av.Set(reflect.Zero(av.Type())) // reset slice to nil 228 return errDecodeArrayElement(i, v, name, err) 229 } 230 } 231 return nil 232} 233