1
16
17 package apiserver
18
19 import (
20 "context"
21 "encoding/json"
22 "math/rand"
23 "testing"
24
25 "github.com/stretchr/testify/require"
26 v1 "k8s.io/api/core/v1"
27 k8sfuzz "k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
28 "k8s.io/apimachinery/pkg/api/meta"
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 "k8s.io/apimachinery/pkg/runtime"
31 "k8s.io/apimachinery/pkg/runtime/serializer"
32 "k8s.io/apimachinery/pkg/util/managedfields"
33 "k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
34 k8stest "k8s.io/kubernetes/pkg/api/testing"
35 )
36
37 func convertToUnstructured(b *testing.B, obj runtime.Object) runtime.Object {
38 converter := managedfields.NewDeducedTypeConverter()
39 typed, err := converter.ObjectToTyped(obj)
40 require.NoError(b, err)
41 res, err := converter.TypedToObject(typed)
42 require.NoError(b, err)
43 return res
44 }
45
46 func doBench(b *testing.B, useUnstructured bool, shortCircuit bool) {
47 var (
48 expectedLarge runtime.Object
49 actualLarge runtime.Object
50 expectedSmall runtime.Object
51 actualSmall runtime.Object
52 )
53
54 scheme := runtime.NewScheme()
55 codecs := serializer.NewCodecFactory(scheme)
56 seed := rand.Int63()
57 fuzzer := k8sfuzz.FuzzerFor(k8stest.FuzzerFuncs, rand.NewSource(seed), codecs)
58 fuzzer.NilChance(0)
59
60 fuzzer.MaxDepth(1000).NilChance(0.2).NumElements(2, 15)
61 pod := &v1.Pod{}
62 fuzzer.Fuzz(pod)
63
64 fuzzer.NilChance(0.2).NumElements(10, 100).MaxDepth(10)
65 deployment := &v1.Endpoints{}
66 fuzzer.Fuzz(deployment)
67
68 bts, err := json.Marshal(deployment)
69 require.NoError(b, err)
70 b.Logf("Small (Deployment): %v bytes", len(bts))
71 bts, err = json.Marshal(pod)
72 require.NoError(b, err)
73 b.Logf("Large (Pod): %v bytes", len(bts))
74
75 expectedLarge = deployment
76 expectedSmall = pod
77
78 if useUnstructured {
79 expectedSmall = convertToUnstructured(b, expectedSmall)
80 expectedLarge = convertToUnstructured(b, expectedLarge)
81 }
82
83 actualLarge = expectedLarge.DeepCopyObject()
84 actualSmall = expectedSmall.DeepCopyObject()
85
86 if shortCircuit {
87
88 now := metav1.Now()
89 extraEntry := &metav1.ManagedFieldsEntry{
90 Manager: "sidecar_controller",
91 Operation: metav1.ManagedFieldsOperationApply,
92 APIVersion: "apps/v1",
93 Time: &now,
94 FieldsType: "FieldsV1",
95 FieldsV1: &metav1.FieldsV1{
96 Raw: []byte(`{"f:metadata":{"f:labels":{"f:sidecar_version":{}}},"f:spec":{"f:template":{"f:spec":{"f:containers":{"k:{\"name\":\"sidecar\"}":{".":{},"f:image":{},"f:name":{}}}}}}}`),
97 },
98 }
99
100 largeMeta, err := meta.Accessor(actualLarge)
101 require.NoError(b, err)
102 largeMeta.SetManagedFields(append(largeMeta.GetManagedFields(), *extraEntry))
103
104 smallMeta, err := meta.Accessor(actualSmall)
105 require.NoError(b, err)
106 smallMeta.SetManagedFields(append(smallMeta.GetManagedFields(), *extraEntry))
107 }
108
109 b.ResetTimer()
110
111 b.Run("Large", func(b2 *testing.B) {
112 for i := 0; i < b2.N; i++ {
113 if _, err := fieldmanager.IgnoreManagedFieldsTimestampsTransformer(
114 context.TODO(),
115 actualLarge,
116 expectedLarge,
117 ); err != nil {
118 b2.Fatal(err)
119 }
120 }
121 })
122
123 b.Run("Small", func(b2 *testing.B) {
124 for i := 0; i < b2.N; i++ {
125 if _, err := fieldmanager.IgnoreManagedFieldsTimestampsTransformer(
126 context.TODO(),
127 actualSmall,
128 expectedSmall,
129 ); err != nil {
130 b2.Fatal(err)
131 }
132 }
133 })
134 }
135
136 func BenchmarkIgnoreManagedFieldsTimestampTransformerStructuredShortCircuit(b *testing.B) {
137 doBench(b, false, true)
138 }
139
140 func BenchmarkIgnoreManagedFieldsTimestampTransformerStructuredWorstCase(b *testing.B) {
141 doBench(b, false, false)
142 }
143
144 func BenchmarkIgnoreManagedFieldsTimestampTransformerUnstructuredShortCircuit(b *testing.B) {
145 doBench(b, true, true)
146 }
147
148 func BenchmarkIgnoreManagedFieldsTimestampTransformerUnstructuredWorstCase(b *testing.B) {
149 doBench(b, true, false)
150 }
151
View as plain text