Browse Source

Merge pull request #10710 from j2gg0s/refactor-lease-bench-test

lease: refactor lease's benchmark.
Xiang Li 6 years ago
parent
commit
f6a9ebe579
2 changed files with 183 additions and 81 deletions
  1. 7 0
      lease/lessor.go
  2. 176 81
      lease/lessor_bench_test.go

+ 7 - 0
lease/lessor.go

@@ -924,3 +924,10 @@ func (fl *FakeLessor) ExpiredLeasesC() <-chan []*Lease { return nil }
 func (fl *FakeLessor) Recover(b backend.Backend, rd RangeDeleter) {}
 func (fl *FakeLessor) Recover(b backend.Backend, rd RangeDeleter) {}
 
 
 func (fl *FakeLessor) Stop() {}
 func (fl *FakeLessor) Stop() {}
+
+type FakeTxnDelete struct {
+	backend.BatchTx
+}
+
+func (ftd *FakeTxnDelete) DeleteRange(key, end []byte) (n, rev int64) { return 0, 0 }
+func (ftd *FakeTxnDelete) End()                                       { ftd.Unlock() }

+ 176 - 81
lease/lessor_bench_test.go

@@ -15,112 +15,207 @@
 package lease
 package lease
 
 
 import (
 import (
+	"math/rand"
 	"os"
 	"os"
 	"testing"
 	"testing"
+	"time"
 
 
 	"go.etcd.io/etcd/mvcc/backend"
 	"go.etcd.io/etcd/mvcc/backend"
 	"go.uber.org/zap"
 	"go.uber.org/zap"
 )
 )
 
 
-func BenchmarkLessorFindExpired1(b *testing.B)       { benchmarkLessorFindExpired(1, b) }
-func BenchmarkLessorFindExpired10(b *testing.B)      { benchmarkLessorFindExpired(10, b) }
-func BenchmarkLessorFindExpired100(b *testing.B)     { benchmarkLessorFindExpired(100, b) }
-func BenchmarkLessorFindExpired1000(b *testing.B)    { benchmarkLessorFindExpired(1000, b) }
-func BenchmarkLessorFindExpired10000(b *testing.B)   { benchmarkLessorFindExpired(10000, b) }
-func BenchmarkLessorFindExpired100000(b *testing.B)  { benchmarkLessorFindExpired(100000, b) }
-func BenchmarkLessorFindExpired1000000(b *testing.B) { benchmarkLessorFindExpired(1000000, b) }
-
-func BenchmarkLessorGrant1(b *testing.B)       { benchmarkLessorGrant(1, b) }
-func BenchmarkLessorGrant10(b *testing.B)      { benchmarkLessorGrant(10, b) }
-func BenchmarkLessorGrant100(b *testing.B)     { benchmarkLessorGrant(100, b) }
-func BenchmarkLessorGrant1000(b *testing.B)    { benchmarkLessorGrant(1000, b) }
-func BenchmarkLessorGrant10000(b *testing.B)   { benchmarkLessorGrant(10000, b) }
-func BenchmarkLessorGrant100000(b *testing.B)  { benchmarkLessorGrant(100000, b) }
-func BenchmarkLessorGrant1000000(b *testing.B) { benchmarkLessorGrant(1000000, b) }
-
-func BenchmarkLessorRenew1(b *testing.B)       { benchmarkLessorRenew(1, b) }
-func BenchmarkLessorRenew10(b *testing.B)      { benchmarkLessorRenew(10, b) }
-func BenchmarkLessorRenew100(b *testing.B)     { benchmarkLessorRenew(100, b) }
-func BenchmarkLessorRenew1000(b *testing.B)    { benchmarkLessorRenew(1000, b) }
-func BenchmarkLessorRenew10000(b *testing.B)   { benchmarkLessorRenew(10000, b) }
-func BenchmarkLessorRenew100000(b *testing.B)  { benchmarkLessorRenew(100000, b) }
-func BenchmarkLessorRenew1000000(b *testing.B) { benchmarkLessorRenew(1000000, b) }
-
-func BenchmarkLessorRevoke1(b *testing.B)       { benchmarkLessorRevoke(1, b) }
-func BenchmarkLessorRevoke10(b *testing.B)      { benchmarkLessorRevoke(10, b) }
-func BenchmarkLessorRevoke100(b *testing.B)     { benchmarkLessorRevoke(100, b) }
-func BenchmarkLessorRevoke1000(b *testing.B)    { benchmarkLessorRevoke(1000, b) }
-func BenchmarkLessorRevoke10000(b *testing.B)   { benchmarkLessorRevoke(10000, b) }
-func BenchmarkLessorRevoke100000(b *testing.B)  { benchmarkLessorRevoke(100000, b) }
-func BenchmarkLessorRevoke1000000(b *testing.B) { benchmarkLessorRevoke(1000000, b) }
-
-func benchmarkLessorFindExpired(size int, b *testing.B) {
-	lg := zap.NewNop()
-	be, tmpPath := backend.NewDefaultTmpBackend()
-	le := newLessor(lg, be, LessorConfig{MinLeaseTTL: minLeaseTTL})
-	defer le.Stop()
-	defer cleanup(be, tmpPath)
-	le.Promote(0)
-	for i := 0; i < size; i++ {
-		le.Grant(LeaseID(i), int64(100+i))
+func BenchmarkLessorGrant1000(b *testing.B)   { benchmarkLessorGrant(1000, b) }
+func BenchmarkLessorGrant100000(b *testing.B) { benchmarkLessorGrant(100000, b) }
+
+func BenchmarkLessorRevoke1000(b *testing.B)   { benchmarkLessorRevoke(1000, b) }
+func BenchmarkLessorRevoke100000(b *testing.B) { benchmarkLessorRevoke(100000, b) }
+
+func BenchmarkLessorRenew1000(b *testing.B)   { benchmarkLessorRenew(1000, b) }
+func BenchmarkLessorRenew100000(b *testing.B) { benchmarkLessorRenew(100000, b) }
+
+// Use findExpired10000 replace findExpired1000, which takes too long.
+func BenchmarkLessorFindExpired10000(b *testing.B)  { benchmarkLessorFindExpired(10000, b) }
+func BenchmarkLessorFindExpired100000(b *testing.B) { benchmarkLessorFindExpired(100000, b) }
+
+func init() {
+	rand.Seed(time.Now().UTC().UnixNano())
+}
+
+const (
+	// minTTL keep lease will not auto expire in benchmark
+	minTTL = 1000
+	// maxTTL control repeat probability of ttls
+	maxTTL = 2000
+)
+
+func randomTTL(n int, min, max int64) (out []int64) {
+	for i := 0; i < n; i++ {
+		out = append(out, rand.Int63n(max-min)+min)
 	}
 	}
-	le.mu.Lock() //Stop the findExpiredLeases call in the runloop
+	return out
+}
+
+// demote lessor from being the primary, but don't change any lease's expiry
+func demote(le *lessor) {
+	le.mu.Lock()
 	defer le.mu.Unlock()
 	defer le.mu.Unlock()
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		le.findExpiredLeases(1000)
-	}
+	close(le.demotec)
+	le.demotec = nil
 }
 }
 
 
-func benchmarkLessorGrant(size int, b *testing.B) {
+// return new lessor and tearDown to release resource
+func setUp() (le *lessor, tearDown func()) {
 	lg := zap.NewNop()
 	lg := zap.NewNop()
 	be, tmpPath := backend.NewDefaultTmpBackend()
 	be, tmpPath := backend.NewDefaultTmpBackend()
-	le := newLessor(lg, be, LessorConfig{MinLeaseTTL: minLeaseTTL})
-	defer le.Stop()
-	defer cleanup(be, tmpPath)
-	for i := 0; i < size; i++ {
-		le.Grant(LeaseID(i), int64(100+i))
-	}
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		le.Grant(LeaseID(i+size), int64(100+i+size))
+	// MinLeaseTTL is negative, so we can grant expired lease in benchmark.
+	// ExpiredLeasesRetryInterval should small, so benchmark of findExpired will recheck expired lease.
+	le = newLessor(lg, be, LessorConfig{MinLeaseTTL: -1000, ExpiredLeasesRetryInterval: 10 * time.Microsecond})
+	le.SetRangeDeleter(func() TxnDelete {
+		ftd := &FakeTxnDelete{be.BatchTx()}
+		ftd.Lock()
+		return ftd
+	})
+	le.Promote(0)
+
+	return le, func() {
+		le.Stop()
+		be.Close()
+		os.Remove(tmpPath)
 	}
 	}
 }
 }
 
 
-func benchmarkLessorRevoke(size int, b *testing.B) {
-	lg := zap.NewNop()
-	be, tmpPath := backend.NewDefaultTmpBackend()
-	le := newLessor(lg, be, LessorConfig{MinLeaseTTL: minLeaseTTL})
-	defer le.Stop()
-	defer cleanup(be, tmpPath)
-	for i := 0; i < size; i++ {
-		le.Grant(LeaseID(i), int64(100+i))
+func benchmarkLessorGrant(benchSize int, b *testing.B) {
+	ttls := randomTTL(benchSize, minTTL, maxTTL)
+
+	var le *lessor
+	var tearDown func()
+
+	b.ResetTimer()
+	for i := 0; i < b.N; {
+		b.StopTimer()
+		if tearDown != nil {
+			tearDown()
+			tearDown = nil
+		}
+		le, tearDown = setUp()
+		b.StartTimer()
+
+		for j := 1; j <= benchSize; j++ {
+			le.Grant(LeaseID(j), ttls[j-1])
+		}
+		i += benchSize
 	}
 	}
-	for i := 0; i < b.N; i++ {
-		le.Grant(LeaseID(i+size), int64(100+i+size))
+	b.StopTimer()
+
+	if tearDown != nil {
+		tearDown()
 	}
 	}
+}
+
+func benchmarkLessorRevoke(benchSize int, b *testing.B) {
+	ttls := randomTTL(benchSize, minTTL, maxTTL)
+
+	var le *lessor
+	var tearDown func()
 	b.ResetTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {
-		le.Revoke(LeaseID(i + size))
+		b.StopTimer()
+		if tearDown != nil {
+			tearDown()
+			tearDown = nil
+		}
+		le, tearDown = setUp()
+		for j := 1; j <= benchSize; j++ {
+			le.Grant(LeaseID(j), ttls[j-1])
+		}
+		b.StartTimer()
+
+		for j := 1; j <= benchSize; j++ {
+			le.Revoke(LeaseID(j))
+		}
+		i += benchSize
 	}
 	}
-}
+	b.StopTimer()
 
 
-func benchmarkLessorRenew(size int, b *testing.B) {
-	lg := zap.NewNop()
-	be, tmpPath := backend.NewDefaultTmpBackend()
-	le := newLessor(lg, be, LessorConfig{MinLeaseTTL: minLeaseTTL})
-	defer le.Stop()
-	defer cleanup(be, tmpPath)
-	for i := 0; i < size; i++ {
-		le.Grant(LeaseID(i), int64(100+i))
+	if tearDown != nil {
+		tearDown()
 	}
 	}
+}
+
+func benchmarkLessorRenew(benchSize int, b *testing.B) {
+	ttls := randomTTL(benchSize, minTTL, maxTTL)
+
+	var le *lessor
+	var tearDown func()
+
 	b.ResetTimer()
 	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		le.Renew(LeaseID(i))
+	for i := 0; i < b.N; {
+		b.StopTimer()
+		if tearDown != nil {
+			tearDown()
+			tearDown = nil
+		}
+		le, tearDown = setUp()
+		for j := 1; j <= benchSize; j++ {
+			le.Grant(LeaseID(j), ttls[j-1])
+		}
+		b.StartTimer()
+
+		for j := 1; j <= benchSize; j++ {
+			le.Renew(LeaseID(j))
+		}
+		i += benchSize
+	}
+	b.StopTimer()
+
+	if tearDown != nil {
+		tearDown()
 	}
 	}
 }
 }
 
 
-func cleanup(b backend.Backend, path string) {
-	b.Close()
-	os.Remove(path)
+func benchmarkLessorFindExpired(benchSize int, b *testing.B) {
+	// 50% lease are expired.
+	ttls := randomTTL(benchSize, -500, 500)
+	findExpiredLimit := 50
+
+	var le *lessor
+	var tearDown func()
+
+	b.ResetTimer()
+	for i := 0; i < b.N; {
+		b.StopTimer()
+		if tearDown != nil {
+			tearDown()
+			tearDown = nil
+		}
+		le, tearDown = setUp()
+		for j := 1; j <= benchSize; j++ {
+			le.Grant(LeaseID(j), ttls[j-1])
+		}
+		// lessor's runLoop should not call findExpired
+		demote(le)
+		b.StartTimer()
+
+		// refresh fixture after pop all expired lease
+		for ; ; i++ {
+			le.mu.Lock()
+			ls := le.findExpiredLeases(findExpiredLimit)
+			if len(ls) == 0 {
+				break
+			}
+			le.mu.Unlock()
+
+			// simulation: revoke lease after expired
+			b.StopTimer()
+			for _, lease := range ls {
+				le.Revoke(lease.ID)
+			}
+			b.StartTimer()
+		}
+	}
+	b.StopTimer()
+
+	if tearDown != nil {
+		tearDown()
+	}
 }
 }