123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- *
- * Copyright 2019 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package wrr
- import (
- "errors"
- "math"
- "math/rand"
- "strconv"
- "testing"
- "github.com/google/go-cmp/cmp"
- "google.golang.org/grpc/internal/grpctest"
- )
- type s struct {
- grpctest.Tester
- }
- func Test(t *testing.T) {
- grpctest.RunSubTests(t, s{})
- }
- const iterCount = 10000
- func equalApproximate(a, b float64) error {
- opt := cmp.Comparer(func(x, y float64) bool {
- delta := math.Abs(x - y)
- mean := math.Abs(x+y) / 2.0
- return delta/mean < 0.05
- })
- if !cmp.Equal(a, b, opt) {
- return errors.New(cmp.Diff(a, b))
- }
- return nil
- }
- func testWRRNext(t *testing.T, newWRR func() WRR) {
- tests := []struct {
- name string
- weights []int64
- }{
- {
- name: "1-1-1",
- weights: []int64{1, 1, 1},
- },
- {
- name: "1-2-3",
- weights: []int64{1, 2, 3},
- },
- {
- name: "5-3-2",
- weights: []int64{5, 3, 2},
- },
- {
- name: "17-23-37",
- weights: []int64{17, 23, 37},
- },
- {
- name: "no items",
- weights: []int64{},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- w := newWRR()
- if len(tt.weights) == 0 {
- if next := w.Next(); next != nil {
- t.Fatalf("w.Next returns non nil value:%v when there is no item", next)
- }
- return
- }
- var sumOfWeights int64
- for i, weight := range tt.weights {
- w.Add(i, weight)
- sumOfWeights += weight
- }
- results := make(map[int]int)
- for i := 0; i < iterCount; i++ {
- results[w.Next().(int)]++
- }
- wantRatio := make([]float64, len(tt.weights))
- for i, weight := range tt.weights {
- wantRatio[i] = float64(weight) / float64(sumOfWeights)
- }
- gotRatio := make([]float64, len(tt.weights))
- for i, count := range results {
- gotRatio[i] = float64(count) / iterCount
- }
- for i := range wantRatio {
- if err := equalApproximate(gotRatio[i], wantRatio[i]); err != nil {
- t.Errorf("%v not equal %v", i, err)
- }
- }
- })
- }
- }
- func (s) TestRandomWRRNext(t *testing.T) {
- testWRRNext(t, NewRandom)
- }
- func (s) TestEdfWrrNext(t *testing.T) {
- testWRRNext(t, NewEDF)
- }
- func BenchmarkRandomWRRNext(b *testing.B) {
- for _, n := range []int{100, 500, 1000} {
- b.Run("equal-weights-"+strconv.Itoa(n)+"-items", func(b *testing.B) {
- w := NewRandom()
- sumOfWeights := n
- for i := 0; i < n; i++ {
- w.Add(i, 1)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- for i := 0; i < sumOfWeights; i++ {
- w.Next()
- }
- }
- })
- }
- var maxWeight int64 = 1024
- for _, n := range []int{100, 500, 1000} {
- b.Run("random-weights-"+strconv.Itoa(n)+"-items", func(b *testing.B) {
- w := NewRandom()
- var sumOfWeights int64
- for i := 0; i < n; i++ {
- weight := rand.Int63n(maxWeight + 1)
- w.Add(i, weight)
- sumOfWeights += weight
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- for i := 0; i < int(sumOfWeights); i++ {
- w.Next()
- }
- }
- })
- }
- itemsNum := 200
- heavyWeight := int64(itemsNum)
- lightWeight := int64(1)
- heavyIndices := []int{0, itemsNum / 2, itemsNum - 1}
- for _, heavyIndex := range heavyIndices {
- b.Run("skew-weights-heavy-index-"+strconv.Itoa(heavyIndex), func(b *testing.B) {
- w := NewRandom()
- var sumOfWeights int64
- for i := 0; i < itemsNum; i++ {
- var weight int64
- if i == heavyIndex {
- weight = heavyWeight
- } else {
- weight = lightWeight
- }
- sumOfWeights += weight
- w.Add(i, weight)
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- for i := 0; i < int(sumOfWeights); i++ {
- w.Next()
- }
- }
- })
- }
- }
- func init() {
- r := rand.New(rand.NewSource(0))
- grpcrandInt63n = r.Int63n
- }
|