mirror of https://github.com/k3s-io/k3s
Merge pull request #19582 from smarterclayton/benchmark_watch
Auto commit by PR queue botpull/6/head
commit
17490c027d
|
@ -374,6 +374,15 @@ See [conformance-test.sh](http://releases.k8s.io/HEAD/hack/conformance-test.sh).
|
||||||
|
|
||||||
[Instructions here](flaky-tests.md)
|
[Instructions here](flaky-tests.md)
|
||||||
|
|
||||||
|
## Benchmarking
|
||||||
|
|
||||||
|
To run benchmark tests, you'll typically use something like:
|
||||||
|
|
||||||
|
$ godep go test ./pkg/apiserver -benchmem -run=XXX -bench=BenchmarkWatch
|
||||||
|
|
||||||
|
The `-run=XXX` prevents normal unit tests for running, while `-bench` is a regexp for selecting which benchmarks to run.
|
||||||
|
See `go test -h` for more instructions on generating profiles from benchmarks.
|
||||||
|
|
||||||
## Regenerating the CLI documentation
|
## Regenerating the CLI documentation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/meta"
|
"k8s.io/kubernetes/pkg/api/meta"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
apiservertesting "k8s.io/kubernetes/pkg/apiserver/testing"
|
apiservertesting "k8s.io/kubernetes/pkg/apiserver/testing"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
@ -158,6 +159,7 @@ func addNewTestTypes() {
|
||||||
api.Scheme.AddKnownTypes(newGroupVersion,
|
api.Scheme.AddKnownTypes(newGroupVersion,
|
||||||
&apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &ListOptions{},
|
&apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &ListOptions{},
|
||||||
&api.DeleteOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
|
&api.DeleteOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
|
||||||
|
api.Scheme.AddKnownTypes(newGroupVersion, &v1.Pod{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -19,16 +19,20 @@ package apiserver
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
|
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
apiservertesting "k8s.io/kubernetes/pkg/apiserver/testing"
|
apiservertesting "k8s.io/kubernetes/pkg/apiserver/testing"
|
||||||
"k8s.io/kubernetes/pkg/fields"
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
@ -424,3 +428,101 @@ func TestWatchHTTPTimeout(t *testing.T) {
|
||||||
t.Errorf("Unexpected non-error")
|
t.Errorf("Unexpected non-error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const benchmarkSeed = 100
|
||||||
|
|
||||||
|
func benchmarkItems() []api.Pod {
|
||||||
|
apiObjectFuzzer := apitesting.FuzzerFor(nil, api.SchemeGroupVersion, rand.NewSource(benchmarkSeed))
|
||||||
|
items := make([]api.Pod, 3)
|
||||||
|
for i := range items {
|
||||||
|
apiObjectFuzzer.Fuzz(&items[i])
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchmarkWatchHTTP measures the cost of serving a watch.
|
||||||
|
func BenchmarkWatchHTTP(b *testing.B) {
|
||||||
|
items := benchmarkItems()
|
||||||
|
|
||||||
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
|
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
dest, _ := url.Parse(server.URL)
|
||||||
|
dest.Path = "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/watch/simples"
|
||||||
|
dest.RawQuery = ""
|
||||||
|
|
||||||
|
request, err := http.NewRequest("GET", dest.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
response, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if response.StatusCode != http.StatusOK {
|
||||||
|
b.Fatalf("Unexpected response %#v", response)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer response.Body.Close()
|
||||||
|
if _, err := io.Copy(ioutil.Discard, response.Body); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
actions := []watch.EventType{watch.Added, watch.Modified, watch.Deleted}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
simpleStorage.fakeWatch.Action(actions[i%len(actions)], &items[i%len(items)])
|
||||||
|
}
|
||||||
|
simpleStorage.fakeWatch.Stop()
|
||||||
|
wg.Wait()
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchmarkWatchWebsocket measures the cost of serving a watch.
|
||||||
|
func BenchmarkWatchWebsocket(b *testing.B) {
|
||||||
|
items := benchmarkItems()
|
||||||
|
|
||||||
|
simpleStorage := &SimpleRESTStorage{}
|
||||||
|
handler := handle(map[string]rest.Storage{"simples": simpleStorage})
|
||||||
|
server := httptest.NewServer(handler)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
dest, _ := url.Parse(server.URL)
|
||||||
|
dest.Scheme = "ws" // Required by websocket, though the server never sees it.
|
||||||
|
dest.Path = "/" + prefix + "/" + newGroupVersion.Group + "/" + newGroupVersion.Version + "/watch/simples"
|
||||||
|
dest.RawQuery = ""
|
||||||
|
|
||||||
|
ws, err := websocket.Dial(dest.String(), "", "http://localhost")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer ws.Close()
|
||||||
|
if _, err := io.Copy(ioutil.Discard, ws); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
actions := []watch.EventType{watch.Added, watch.Modified, watch.Deleted}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
simpleStorage.fakeWatch.Action(actions[i%len(actions)], &items[i%len(items)])
|
||||||
|
}
|
||||||
|
simpleStorage.fakeWatch.Stop()
|
||||||
|
wg.Wait()
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue