Merge pull request #113326 from mborsz/bench3

Add benchmark for json.compact high cpu usage in watch
This commit is contained in:
Kubernetes Prow Robot 2022-10-27 20:20:29 -07:00 committed by GitHub
commit 08644a12b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -17,6 +17,7 @@ limitations under the License.
package endpoints package endpoints
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -38,6 +39,7 @@ import (
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/streaming" "k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@ -878,7 +880,7 @@ func BenchmarkWatchHTTP(b *testing.B) {
item.Name = fmt.Sprintf("reasonable-name-%d", i) item.Name = fmt.Sprintf("reasonable-name-%d", i)
} }
runWatchHTTPBenchmark(b, items) runWatchHTTPBenchmark(b, toObjectSlice(items), "")
} }
func BenchmarkWatchHTTP_UTF8(b *testing.B) { func BenchmarkWatchHTTP_UTF8(b *testing.B) {
@ -891,10 +893,18 @@ func BenchmarkWatchHTTP_UTF8(b *testing.B) {
item.Name = fmt.Sprintf("翏Ŏ熡韐-%d", i) item.Name = fmt.Sprintf("翏Ŏ熡韐-%d", i)
} }
runWatchHTTPBenchmark(b, items) runWatchHTTPBenchmark(b, toObjectSlice(items), "")
} }
func runWatchHTTPBenchmark(b *testing.B, items []example.Pod) { func toObjectSlice(in []example.Pod) []runtime.Object {
var res []runtime.Object
for _, pod := range in {
res = append(res, &pod)
}
return res
}
func runWatchHTTPBenchmark(b *testing.B, items []runtime.Object, contentType string) {
simpleStorage := &SimpleRESTStorage{} simpleStorage := &SimpleRESTStorage{}
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) handler := handle(map[string]rest.Storage{"simples": simpleStorage})
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
@ -909,6 +919,8 @@ func runWatchHTTPBenchmark(b *testing.B, items []example.Pod) {
if err != nil { if err != nil {
b.Fatalf("unexpected error: %v", err) b.Fatalf("unexpected error: %v", err)
} }
request.Header.Add("Accept", contentType)
response, err := client.Do(request) response, err := client.Do(request)
if err != nil { if err != nil {
b.Fatalf("unexpected error: %v", err) b.Fatalf("unexpected error: %v", err)
@ -931,7 +943,7 @@ func runWatchHTTPBenchmark(b *testing.B, items []example.Pod) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
simpleStorage.fakeWatch.Action(actions[i%len(actions)], &items[i%len(items)]) simpleStorage.fakeWatch.Action(actions[i%len(actions)], items[i%len(items)])
} }
simpleStorage.fakeWatch.Stop() simpleStorage.fakeWatch.Stop()
wg.Wait() wg.Wait()
@ -982,47 +994,63 @@ func BenchmarkWatchWebsocket(b *testing.B) {
func BenchmarkWatchProtobuf(b *testing.B) { func BenchmarkWatchProtobuf(b *testing.B) {
items := benchmarkItems(b) items := benchmarkItems(b)
simpleStorage := &SimpleRESTStorage{} runWatchHTTPBenchmark(b, toObjectSlice(items), "application/vnd.kubernetes.protobuf")
handler := handle(map[string]rest.Storage{"simples": simpleStorage}) }
server := httptest.NewServer(handler)
defer server.Close() type fakeCachingObject struct {
client := http.Client{} obj runtime.Object
dest, _ := url.Parse(server.URL) once sync.Once
dest.Path = "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/watch/simples" raw []byte
dest.RawQuery = "" err error
}
request, err := http.NewRequest("GET", dest.String(), nil)
if err != nil { func (f *fakeCachingObject) CacheEncode(_ runtime.Identifier, encode func(runtime.Object, io.Writer) error, w io.Writer) error {
b.Fatalf("unexpected error: %v", err) f.once.Do(func() {
} buffer := bytes.NewBuffer(nil)
request.Header.Set("Accept", "application/vnd.kubernetes.protobuf") f.err = encode(f.obj, buffer)
response, err := client.Do(request) f.raw = buffer.Bytes()
if err != nil { })
b.Fatalf("unexpected error: %v", err)
} if f.err != nil {
if response.StatusCode != http.StatusOK { return f.err
body, _ := ioutil.ReadAll(response.Body) }
b.Fatalf("Unexpected response %#v\n%s", response, body)
} _, err := w.Write(f.raw)
return err
wg := sync.WaitGroup{} }
wg.Add(1)
go func() { func (f *fakeCachingObject) GetObject() runtime.Object {
defer response.Body.Close() return f.obj
if _, err := io.Copy(ioutil.Discard, response.Body); err != nil { }
b.Error(err)
} func (f *fakeCachingObject) GetObjectKind() schema.ObjectKind {
wg.Done() return f.obj.GetObjectKind()
}() }
actions := []watch.EventType{watch.Added, watch.Modified, watch.Deleted} func (f *fakeCachingObject) DeepCopyObject() runtime.Object {
return &fakeCachingObject{obj: f.obj.DeepCopyObject()}
b.ResetTimer() }
for i := 0; i < b.N; i++ {
simpleStorage.fakeWatch.Action(actions[i%len(actions)], &items[i%len(items)]) var _ runtime.CacheableObject = &fakeCachingObject{}
} var _ runtime.Object = &fakeCachingObject{}
simpleStorage.fakeWatch.Stop()
wg.Wait() func wrapCachingObject(in []example.Pod) []runtime.Object {
b.StopTimer() var res []runtime.Object
for _, pod := range in {
res = append(res, &fakeCachingObject{obj: &pod})
}
return res
}
func BenchmarkWatchCachingObjectJSON(b *testing.B) {
items := benchmarkItems(b)
runWatchHTTPBenchmark(b, wrapCachingObject(items), "")
}
func BenchmarkWatchCachingObjectProtobuf(b *testing.B) {
items := benchmarkItems(b)
runWatchHTTPBenchmark(b, wrapCachingObject(items), "application/vnd.kubernetes.protobuf")
} }