Merge pull request #73973 from smarterclayton/fix_benchmark

Fix the unstructured conversion benchmarks to be correct
pull/564/head
Kubernetes Prow Robot 2019-02-15 07:52:54 -08:00 committed by GitHub
commit 1878fae050
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 26 deletions

View File

@ -19,11 +19,13 @@ package testing
import ( import (
"math/rand" "math/rand"
"reflect" "reflect"
"sort"
"testing" "testing"
"github.com/google/gofuzz" fuzz "github.com/google/gofuzz"
jsoniter "github.com/json-iterator/go"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/apitesting/fuzzer" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
apiequality "k8s.io/apimachinery/pkg/api/equality" apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
@ -99,7 +101,7 @@ func doRoundTrip(t *testing.T, internalVersion schema.GroupVersion, externalVers
return return
} }
newUnstr, err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).ToUnstructured(item) newUnstr, err := runtime.DefaultUnstructuredConverter.ToUnstructured(item)
if err != nil { if err != nil {
t.Errorf("ToUnstructured failed: %v", err) t.Errorf("ToUnstructured failed: %v", err)
return return
@ -163,7 +165,7 @@ func TestRoundTripWithEmptyCreationTimestamp(t *testing.T) {
// attempt to re-convert unstructured object - conversion should not fail // attempt to re-convert unstructured object - conversion should not fail
// based on empty metadata fields, such as creationTimestamp // based on empty metadata fields, such as creationTimestamp
newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) newObj := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object)
err = runtime.NewTestUnstructuredConverter(apiequality.Semantic).FromUnstructured(unstructObj.Object, newObj) err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.Object, newObj)
if err != nil { if err != nil {
t.Fatalf("FromUnstructured failed: %v", err) t.Fatalf("FromUnstructured failed: %v", err)
} }
@ -171,44 +173,160 @@ func TestRoundTripWithEmptyCreationTimestamp(t *testing.T) {
} }
} }
func BenchmarkToFromUnstructured(b *testing.B) { func BenchmarkToUnstructured(b *testing.B) {
items := benchmarkItems(b) items := benchmarkItems(b)
size := len(items) size := len(items)
convertor := runtime.DefaultUnstructuredConverter
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
unstr, err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).ToUnstructured(&items[i%size]) unstr, err := convertor.ToUnstructured(&items[i%size])
if err != nil { if err != nil || unstr == nil {
b.Fatalf("unexpected error: %v", err)
}
obj := v1.Pod{}
if err := runtime.NewTestUnstructuredConverter(apiequality.Semantic).FromUnstructured(unstr, &obj); err != nil {
b.Fatalf("unexpected error: %v", err) b.Fatalf("unexpected error: %v", err)
} }
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkToFromUnstructuredViaJSON(b *testing.B) { func BenchmarkFromUnstructured(b *testing.B) {
items := benchmarkItems(b) items := benchmarkItems(b)
convertor := runtime.DefaultUnstructuredConverter
var unstr []map[string]interface{}
for i := range items {
item, err := convertor.ToUnstructured(&items[i])
if err != nil || item == nil {
b.Fatalf("unexpected error: %v", err)
}
unstr = append(unstr, item)
}
size := len(items) size := len(items)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
data, err := json.Marshal(&items[i%size])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
unstr := map[string]interface{}{}
if err := json.Unmarshal(data, &unstr); err != nil {
b.Fatalf("unexpected error: %v", err)
}
data, err = json.Marshal(unstr)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
obj := v1.Pod{} obj := v1.Pod{}
if err := json.Unmarshal(data, &obj); err != nil { if err := convertor.FromUnstructured(unstr[i%size], &obj); err != nil {
b.Fatalf("unexpected error: %v", err) b.Fatalf("unexpected error: %v", err)
} }
} }
b.StopTimer() b.StopTimer()
} }
func BenchmarkToUnstructuredViaJSON(b *testing.B) {
items := benchmarkItems(b)
var data [][]byte
for i := range items {
item, err := json.Marshal(&items[i])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
data = append(data, item)
}
size := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
unstr := map[string]interface{}{}
if err := json.Unmarshal(data[i%size], &unstr); err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
b.StopTimer()
}
func BenchmarkFromUnstructuredViaJSON(b *testing.B) {
items := benchmarkItems(b)
var unstr []map[string]interface{}
for i := range items {
data, err := json.Marshal(&items[i])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
item := map[string]interface{}{}
if err := json.Unmarshal(data, &item); err != nil {
b.Fatalf("unexpected error: %v", err)
}
unstr = append(unstr, item)
}
size := len(items)
b.ResetTimer()
for i := 0; i < b.N; i++ {
item, err := json.Marshal(unstr[i%size])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
obj := v1.Pod{}
if err := json.Unmarshal(item, &obj); err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
b.StopTimer()
}
func BenchmarkToUnstructuredViaJSONIter(b *testing.B) {
items := benchmarkItems(b)
size := len(items)
var keys []string
for k := range jsonIterConfig {
keys = append(keys, k)
}
sort.Strings(keys)
for _, name := range keys {
c := jsonIterConfig[name]
b.Run(name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
data, err := c.Marshal(&items[i%size])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
unstr := map[string]interface{}{}
if err := c.Unmarshal(data, &unstr); err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
b.StopTimer()
})
}
}
var jsonIterConfig = map[string]jsoniter.API{
"default": jsoniter.ConfigDefault,
"fastest": jsoniter.ConfigFastest,
"compat": jsoniter.ConfigCompatibleWithStandardLibrary,
}
func BenchmarkFromUnstructuredViaJSONIter(b *testing.B) {
items := benchmarkItems(b)
var unstr []map[string]interface{}
for i := range items {
data, err := jsoniter.Marshal(&items[i])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
item := map[string]interface{}{}
if err := json.Unmarshal(data, &item); err != nil {
b.Fatalf("unexpected error: %v", err)
}
unstr = append(unstr, item)
}
size := len(items)
var keys []string
for k := range jsonIterConfig {
keys = append(keys, k)
}
sort.Strings(keys)
for _, name := range keys {
c := jsonIterConfig[name]
b.Run(name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
item, err := c.Marshal(unstr[i%size])
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
obj := v1.Pod{}
if err := c.Unmarshal(item, &obj); err != nil {
b.Fatalf("unexpected error: %v", err)
}
}
b.StopTimer()
})
}
}

View File

@ -746,7 +746,7 @@ func isZero(v reflect.Value) bool {
func structToUnstructured(sv, dv reflect.Value) error { func structToUnstructured(sv, dv reflect.Value) error {
st, dt := sv.Type(), dv.Type() st, dt := sv.Type(), dv.Type()
if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 { if dt.Kind() == reflect.Interface && dv.NumMethod() == 0 {
dv.Set(reflect.MakeMap(mapStringInterfaceType)) dv.Set(reflect.MakeMapWithSize(mapStringInterfaceType, st.NumField()))
dv = dv.Elem() dv = dv.Elem()
dt = dv.Type() dt = dv.Type()
} }