From 6a451071932b97807bc4070ba83d130d4d357139 Mon Sep 17 00:00:00 2001
From: Leo Balduf <balduf@hm.edu>
Date: Thu, 11 Aug 2016 20:02:10 -0400
Subject: [PATCH] make benchmarks parallel, fix memory benchmarks

---
 storage/memory/peer_store_test.go |  56 +++++-----
 storage/storage_bench.go          | 168 +++++++++++++++++-------------
 2 files changed, 129 insertions(+), 95 deletions(-)

diff --git a/storage/memory/peer_store_test.go b/storage/memory/peer_store_test.go
index df3a0c1..d85be46 100644
--- a/storage/memory/peer_store_test.go
+++ b/storage/memory/peer_store_test.go
@@ -6,27 +6,35 @@ import (
 	s "github.com/jzelinskie/trakr/storage"
 )
 
-func BenchmarkPut(b *testing.B)                        { s.Put(b, &peerStore{}) }
-func BenchmarkPut1k(b *testing.B)                      { s.Put1k(b, &peerStore{}) }
-func BenchmarkPut1kInfohash(b *testing.B)              { s.Put1kInfohash(b, &peerStore{}) }
-func BenchmarkPut1kInfohash1k(b *testing.B)            { s.Put1kInfohash1k(b, &peerStore{}) }
-func BenchmarkPutDelete(b *testing.B)                  { s.PutDelete(b, &peerStore{}) }
-func BenchmarkPutDelete1k(b *testing.B)                { s.PutDelete1k(b, &peerStore{}) }
-func BenchmarkPutDelete1kInfohash(b *testing.B)        { s.PutDelete1kInfohash(b, &peerStore{}) }
-func BenchmarkPutDelete1kInfohash1k(b *testing.B)      { s.PutDelete1kInfohash1k(b, &peerStore{}) }
-func BenchmarkDeleteNonexist(b *testing.B)             { s.DeleteNonexist(b, &peerStore{}) }
-func BenchmarkDeleteNonexist1k(b *testing.B)           { s.DeleteNonexist1k(b, &peerStore{}) }
-func BenchmarkDeleteNonexist1kInfohash(b *testing.B)   { s.DeleteNonexist1kInfohash(b, &peerStore{}) }
-func BenchmarkDeleteNonexist1kInfohash1k(b *testing.B) { s.DeleteNonexist1kInfohash1k(b, &peerStore{}) }
-func BenchmarkGradDelete(b *testing.B)                 { s.GradDelete(b, &peerStore{}) }
-func BenchmarkGradDelete1k(b *testing.B)               { s.GradDelete1k(b, &peerStore{}) }
-func BenchmarkGradDelete1kInfohash(b *testing.B)       { s.GradDelete1kInfohash(b, &peerStore{}) }
-func BenchmarkGradDelete1kInfohash1k(b *testing.B)     { s.GradDelete1kInfohash1k(b, &peerStore{}) }
-func BenchmarkGradNonexist(b *testing.B)               { s.GradNonexist(b, &peerStore{}) }
-func BenchmarkGradNonexist1k(b *testing.B)             { s.GradNonexist1k(b, &peerStore{}) }
-func BenchmarkGradNonexist1kInfohash(b *testing.B)     { s.GradNonexist1kInfohash(b, &peerStore{}) }
-func BenchmarkGradNonexist1kInfohash1k(b *testing.B)   { s.GradNonexist1kInfohash1k(b, &peerStore{}) }
-func BenchmarkAnnounceLeecher(b *testing.B)            { s.AnnounceLeecher(b, &peerStore{}) }
-func BenchmarkAnnounceLeecher1kInfohash(b *testing.B)  { s.AnnounceLeecher1kInfohash(b, &peerStore{}) }
-func BenchmarkAnnounceSeeder(b *testing.B)             { s.AnnounceSeeder(b, &peerStore{}) }
-func BenchmarkAnnounceSeeder1kInfohash(b *testing.B)   { s.AnnounceSeeder1kInfohash(b, &peerStore{}) }
+func createNew() s.PeerStore {
+	ps, err := New(Config{ShardCount: 1024})
+	if err != nil {
+		panic(err)
+	}
+	return ps
+}
+
+func BenchmarkPut(b *testing.B)                        { s.Put(b, createNew()) }
+func BenchmarkPut1k(b *testing.B)                      { s.Put1k(b, createNew()) }
+func BenchmarkPut1kInfohash(b *testing.B)              { s.Put1kInfohash(b, createNew()) }
+func BenchmarkPut1kInfohash1k(b *testing.B)            { s.Put1kInfohash1k(b, createNew()) }
+func BenchmarkPutDelete(b *testing.B)                  { s.PutDelete(b, createNew()) }
+func BenchmarkPutDelete1k(b *testing.B)                { s.PutDelete1k(b, createNew()) }
+func BenchmarkPutDelete1kInfohash(b *testing.B)        { s.PutDelete1kInfohash(b, createNew()) }
+func BenchmarkPutDelete1kInfohash1k(b *testing.B)      { s.PutDelete1kInfohash1k(b, createNew()) }
+func BenchmarkDeleteNonexist(b *testing.B)             { s.DeleteNonexist(b, createNew()) }
+func BenchmarkDeleteNonexist1k(b *testing.B)           { s.DeleteNonexist1k(b, createNew()) }
+func BenchmarkDeleteNonexist1kInfohash(b *testing.B)   { s.DeleteNonexist1kInfohash(b, createNew()) }
+func BenchmarkDeleteNonexist1kInfohash1k(b *testing.B) { s.DeleteNonexist1kInfohash1k(b, createNew()) }
+func BenchmarkPutGradDelete(b *testing.B)              { s.PutGradDelete(b, createNew()) }
+func BenchmarkPutGradDelete1k(b *testing.B)            { s.PutGradDelete1k(b, createNew()) }
+func BenchmarkPutGradDelete1kInfohash(b *testing.B)    { s.PutGradDelete1kInfohash(b, createNew()) }
+func BenchmarkPutGradDelete1kInfohash1k(b *testing.B)  { s.PutGradDelete1kInfohash1k(b, createNew()) }
+func BenchmarkGradNonexist(b *testing.B)               { s.GradNonexist(b, createNew()) }
+func BenchmarkGradNonexist1k(b *testing.B)             { s.GradNonexist1k(b, createNew()) }
+func BenchmarkGradNonexist1kInfohash(b *testing.B)     { s.GradNonexist1kInfohash(b, createNew()) }
+func BenchmarkGradNonexist1kInfohash1k(b *testing.B)   { s.GradNonexist1kInfohash1k(b, createNew()) }
+func BenchmarkAnnounceLeecher(b *testing.B)            { s.AnnounceLeecher(b, createNew()) }
+func BenchmarkAnnounceLeecher1kInfohash(b *testing.B)  { s.AnnounceLeecher1kInfohash(b, createNew()) }
+func BenchmarkAnnounceSeeder(b *testing.B)             { s.AnnounceSeeder(b, createNew()) }
+func BenchmarkAnnounceSeeder1kInfohash(b *testing.B)   { s.AnnounceSeeder1kInfohash(b, createNew()) }
diff --git a/storage/storage_bench.go b/storage/storage_bench.go
index c76bd41..316a425 100644
--- a/storage/storage_bench.go
+++ b/storage/storage_bench.go
@@ -1,8 +1,10 @@
 package storage
 
 import (
-	"fmt"
+	"math/rand"
 	"net"
+	"runtime"
+	"sync/atomic"
 	"testing"
 
 	"github.com/jzelinskie/trakr/bittorrent"
@@ -14,25 +16,37 @@ type benchData struct {
 }
 
 func generateInfohashes() (a [1000]bittorrent.InfoHash) {
-	b := make([]byte, 2)
+	r := rand.New(rand.NewSource(0))
 	for i := range a {
-		b[0] = byte(i)
-		b[1] = byte(i >> 8)
-		a[i] = bittorrent.InfoHash([20]byte{b[0], b[1]})
+		b := [20]byte{}
+		n, err := r.Read(b[:])
+		if err != nil || n != 20 {
+			panic("unable to create random bytes")
+		}
+		a[i] = bittorrent.InfoHash(b)
 	}
 
 	return
 }
 
 func generatePeers() (a [1000]bittorrent.Peer) {
-	b := make([]byte, 2)
+	r := rand.New(rand.NewSource(0))
 	for i := range a {
-		b[0] = byte(i)
-		b[1] = byte(i >> 8)
+		ip := make([]byte, 4)
+		n, err := r.Read(ip)
+		if err != nil || n != 4 {
+			panic("unable to create random bytes")
+		}
+		id := [20]byte{}
+		n, err = r.Read(id[:])
+		if err != nil || n != 20 {
+			panic("unable to create random bytes")
+		}
+		port := uint16(r.Uint32())
 		a[i] = bittorrent.Peer{
-			ID:   bittorrent.PeerID([20]byte{b[0], b[1]}),
-			IP:   net.ParseIP(fmt.Sprintf("64.%d.%d.64", b[0], b[1])),
-			Port: uint16(i),
+			ID:   bittorrent.PeerID(id),
+			IP:   net.IP(ip),
+			Port: port,
 		}
 	}
 
@@ -42,53 +56,67 @@ func generatePeers() (a [1000]bittorrent.Peer) {
 type executionFunc func(int, PeerStore, *benchData) error
 type setupFunc func(PeerStore, *benchData) error
 
-func runBenchmark(b *testing.B, ps PeerStore, sf setupFunc, ef executionFunc) {
+func runBenchmark(b *testing.B, ps PeerStore, parallel bool, sf setupFunc, ef executionFunc) {
 	bd := &benchData{generateInfohashes(), generatePeers()}
+	spacing := int32(1000 / runtime.NumCPU())
 	if sf != nil {
 		err := sf(ps, bd)
 		if err != nil {
 			b.Fatal(err)
 		}
 	}
+	offset := int32(0)
+
 	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		err := ef(i, ps, bd)
-		if err != nil {
-			b.Fatal(err)
+	if parallel {
+		b.RunParallel(func(pb *testing.PB) {
+			i := int(atomic.AddInt32(&offset, spacing))
+			for pb.Next() {
+				err := ef(i, ps, bd)
+				if err != nil {
+					b.Fatal(err)
+				}
+				i++
+			}
+		})
+	} else {
+		for i := 0; i < b.N; i++ {
+			err := ef(i, ps, bd)
+			if err != nil {
+				b.Fatal(err)
+			}
 		}
 	}
 	b.StopTimer()
 }
 
 func Put(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
 		return ps.PutSeeder(bd.infohashes[0], bd.peers[0])
 	})
 }
 
 func Put1k(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
 		return ps.PutSeeder(bd.infohashes[0], bd.peers[i%1000])
 	})
 }
 
 func Put1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
 		return ps.PutSeeder(bd.infohashes[i%1000], bd.peers[0])
 	})
 }
 
 func Put1kInfohash1k(b *testing.B, ps PeerStore) {
-	j := 0
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		err := ps.PutSeeder(bd.infohashes[i%1000], bd.peers[j%1000])
-		j += 3
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		err := ps.PutSeeder(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		return err
 	})
 }
 
 func PutDelete(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutSeeder(bd.infohashes[0], bd.peers[0])
 		if err != nil {
 			return err
@@ -98,7 +126,7 @@ func PutDelete(b *testing.B, ps PeerStore) {
 }
 
 func PutDelete1k(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutSeeder(bd.infohashes[0], bd.peers[i%1000])
 		if err != nil {
 			return err
@@ -108,7 +136,7 @@ func PutDelete1k(b *testing.B, ps PeerStore) {
 }
 
 func PutDelete1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutSeeder(bd.infohashes[i%1000], bd.peers[0])
 		if err != nil {
 		}
@@ -117,74 +145,74 @@ func PutDelete1kInfohash(b *testing.B, ps PeerStore) {
 }
 
 func PutDelete1kInfohash1k(b *testing.B, ps PeerStore) {
-	j := 0
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		err := ps.PutSeeder(bd.infohashes[i%1000], bd.peers[j%1000])
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
+		err := ps.PutSeeder(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		if err != nil {
 			return err
 		}
-		err = ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[j%1000])
-		j += 3
+		err = ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		return err
 	})
 }
 
 func DeleteNonexist(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.DeleteSeeder(bd.infohashes[0], bd.peers[0])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.DeleteSeeder(bd.infohashes[0], bd.peers[0])
+		return nil
 	})
 }
 
 func DeleteNonexist1k(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.DeleteSeeder(bd.infohashes[0], bd.peers[i%1000])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.DeleteSeeder(bd.infohashes[0], bd.peers[i%1000])
+		return nil
 	})
 }
 
 func DeleteNonexist1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[0])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[0])
+		return nil
 	})
 }
 
 func DeleteNonexist1kInfohash1k(b *testing.B, ps PeerStore) {
-	j := 0
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		err := ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[j%1000])
-		j += 3
-		return err
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
+		return nil
 	})
 }
 
 func GradNonexist(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.GraduateLeecher(bd.infohashes[0], bd.peers[0])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.GraduateLeecher(bd.infohashes[0], bd.peers[0])
+		return nil
 	})
 }
 
 func GradNonexist1k(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.GraduateLeecher(bd.infohashes[0], bd.peers[i%1000])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.GraduateLeecher(bd.infohashes[0], bd.peers[i%1000])
+		return nil
 	})
 }
 
 func GradNonexist1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		return ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[0])
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[0])
+		return nil
 	})
 }
 
 func GradNonexist1kInfohash1k(b *testing.B, ps PeerStore) {
-	j := 0
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		err := ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[j%1000])
-		j += 3
-		return err
+	runBenchmark(b, ps, true, nil, func(i int, ps PeerStore, bd *benchData) error {
+		ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
+		return nil
 	})
 }
 
-func GradDelete(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+func PutGradDelete(b *testing.B, ps PeerStore) {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutLeecher(bd.infohashes[0], bd.peers[0])
 		if err != nil {
 			return err
@@ -197,8 +225,8 @@ func GradDelete(b *testing.B, ps PeerStore) {
 	})
 }
 
-func GradDelete1k(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+func PutGradDelete1k(b *testing.B, ps PeerStore) {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutLeecher(bd.infohashes[0], bd.peers[i%1000])
 		if err != nil {
 			return err
@@ -211,8 +239,8 @@ func GradDelete1k(b *testing.B, ps PeerStore) {
 	})
 }
 
-func GradDelete1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
+func PutGradDelete1kInfohash(b *testing.B, ps PeerStore) {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
 		err := ps.PutLeecher(bd.infohashes[i%1000], bd.peers[0])
 		if err != nil {
 			return err
@@ -225,24 +253,22 @@ func GradDelete1kInfohash(b *testing.B, ps PeerStore) {
 	})
 }
 
-func GradDelete1kInfohash1k(b *testing.B, ps PeerStore) {
-	j := 0
-	runBenchmark(b, ps, nil, func(i int, ps PeerStore, bd *benchData) error {
-		err := ps.PutLeecher(bd.infohashes[i%1000], bd.peers[j%1000])
+func PutGradDelete1kInfohash1k(b *testing.B, ps PeerStore) {
+	runBenchmark(b, ps, false, nil, func(i int, ps PeerStore, bd *benchData) error {
+		err := ps.PutLeecher(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		if err != nil {
 			return err
 		}
-		err = ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[j%1000])
+		err = ps.GraduateLeecher(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		if err != nil {
 			return err
 		}
-		err = ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[j%1000])
-		j += 3
+		err = ps.DeleteSeeder(bd.infohashes[i%1000], bd.peers[(i*3)%1000])
 		return err
 	})
 }
 
-func generateAnnounceData(ps PeerStore, bd *benchData) error {
+func putPeers(ps PeerStore, bd *benchData) error {
 	for i := 0; i < 1000; i++ {
 		for j := 0; j < 1000; j++ {
 			var err error
@@ -260,28 +286,28 @@ func generateAnnounceData(ps PeerStore, bd *benchData) error {
 }
 
 func AnnounceLeecher(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, generateAnnounceData, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, putPeers, func(i int, ps PeerStore, bd *benchData) error {
 		_, err := ps.AnnouncePeers(bd.infohashes[0], false, 50, bd.peers[0])
 		return err
 	})
 }
 
 func AnnounceLeecher1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, generateAnnounceData, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, putPeers, func(i int, ps PeerStore, bd *benchData) error {
 		_, err := ps.AnnouncePeers(bd.infohashes[i%1000], false, 50, bd.peers[0])
 		return err
 	})
 }
 
 func AnnounceSeeder(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, generateAnnounceData, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, putPeers, func(i int, ps PeerStore, bd *benchData) error {
 		_, err := ps.AnnouncePeers(bd.infohashes[0], true, 50, bd.peers[0])
 		return err
 	})
 }
 
 func AnnounceSeeder1kInfohash(b *testing.B, ps PeerStore) {
-	runBenchmark(b, ps, generateAnnounceData, func(i int, ps PeerStore, bd *benchData) error {
+	runBenchmark(b, ps, true, putPeers, func(i int, ps PeerStore, bd *benchData) error {
 		_, err := ps.AnnouncePeers(bd.infohashes[i%1000], true, 50, bd.peers[0])
 		return err
 	})