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 BenchmarkDecodeArray(b *testing.B) { 102 for _, size := range []int{1, 10, 100, 1000} { 103 vals := make([]*proto3.Value, size) 104 for i := 0; i < size; i++ { 105 vals[i] = dateProto(d1) 106 } 107 lv := &proto3.ListValue{Values: vals} 108 b.Run(strconv.Itoa(size), func(b *testing.B) { 109 for _, s := range []struct { 110 name string 111 decode func(*proto3.ListValue) 112 }{ 113 {"DateDirect", decodeArrayDateDirect}, 114 {"DateFunc", decodeArrayDateFunc}, 115 {"DateReflect", decodeArrayDateReflect}, 116 {"StringDecodeStringArray", decodeStringArrayWrap}, 117 {"StringDirect", decodeArrayStringDirect}, 118 {"StringFunc", decodeArrayStringFunc}, 119 {"StringReflect", decodeArrayStringReflect}, 120 } { 121 b.Run(s.name, func(b *testing.B) { 122 for i := 0; i < b.N; i++ { 123 s.decode(lv) 124 } 125 }) 126 } 127 }) 128 129 } 130} 131 132func decodeArrayDateDirect(pb *proto3.ListValue) { 133 a := make([]civil.Date, len(pb.Values)) 134 t := dateType() 135 for i, v := range pb.Values { 136 if err := decodeValue(v, t, &a[i]); err != nil { 137 panic(err) 138 } 139 } 140} 141 142func decodeArrayDateFunc(pb *proto3.ListValue) { 143 a := make([]civil.Date, len(pb.Values)) 144 if err := decodeArrayFunc(pb, "DATE", dateType(), func(i int) interface{} { return &a[i] }); err != nil { 145 panic(err) 146 } 147} 148 149func decodeArrayDateReflect(pb *proto3.ListValue) { 150 var a []civil.Date 151 if err := decodeArrayReflect(pb, "DATE", dateType(), &a); err != nil { 152 panic(err) 153 } 154} 155 156func decodeStringArrayWrap(pb *proto3.ListValue) { 157 if _, err := decodeStringArray(pb); err != nil { 158 panic(err) 159 } 160} 161 162func decodeArrayStringDirect(pb *proto3.ListValue) { 163 a := make([]string, len(pb.Values)) 164 t := stringType() 165 for i, v := range pb.Values { 166 if err := decodeValue(v, t, &a[i]); err != nil { 167 panic(err) 168 } 169 } 170} 171 172func decodeArrayStringFunc(pb *proto3.ListValue) { 173 a := make([]string, len(pb.Values)) 174 if err := decodeArrayFunc(pb, "STRING", stringType(), func(i int) interface{} { return &a[i] }); err != nil { 175 panic(err) 176 } 177} 178 179func decodeArrayStringReflect(pb *proto3.ListValue) { 180 var a []string 181 if err := decodeArrayReflect(pb, "STRING", stringType(), &a); err != nil { 182 panic(err) 183 } 184} 185 186func decodeArrayFunc(pb *proto3.ListValue, name string, typ *sppb.Type, elptr func(int) interface{}) error { 187 if pb == nil { 188 return errNilListValue(name) 189 } 190 for i, v := range pb.Values { 191 if err := decodeValue(v, typ, elptr(i)); err != nil { 192 return errDecodeArrayElement(i, v, name, err) 193 } 194 } 195 return nil 196} 197 198func decodeArrayReflect(pb *proto3.ListValue, name string, typ *sppb.Type, aptr interface{}) error { 199 if pb == nil { 200 return errNilListValue(name) 201 } 202 av := reflect.ValueOf(aptr).Elem() 203 av.Set(reflect.MakeSlice(av.Type(), len(pb.Values), len(pb.Values))) 204 for i, v := range pb.Values { 205 if err := decodeValue(v, typ, av.Index(i).Addr().Interface()); err != nil { 206 av.Set(reflect.Zero(av.Type())) // reset slice to nil 207 return errDecodeArrayElement(i, v, name, err) 208 } 209 } 210 return nil 211} 212