github.com/Lz-Gustavo/beemport@v0.0.0-20220203143007-a29c25c47274/conctable_bench_test.go (about) 1 package beemport 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "os" 8 "runtime" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/Lz-Gustavo/beemport/pb" 14 ) 15 16 // Dear dev, avoid crash on your IDE by running with: 17 // go test -run none -bench BenchmarkAlgosThroughput -benchtime 1ns -benchmem -v 18 func BenchmarkConcTableThroughput(b *testing.B) { 19 b.SetParallelism(runtime.NumCPU()) 20 numCommands, diffKeys, writePercent := uint64(1000000), 1000, 50 21 log := make(chan *pb.Entry, numCommands) 22 23 // dummy goroutine that creates a random log of commands 24 go createRandomLog(numCommands, diffKeys, writePercent, log) 25 26 chA := make(chan *pb.Entry) 27 chB := make(chan *pb.Entry) 28 29 wg := &sync.WaitGroup{} 30 mu := &sync.Mutex{} 31 wg.Add(2) 32 33 go runTraditionalLog(chA, numCommands, mu, wg) 34 go runConcTable(chB, numCommands, mu, wg) 35 36 // fan-out that output to the different goroutines 37 go splitIntoWorkers(log, chA, chB) 38 39 // close the input log channel once all algorithms are executed 40 wg.Wait() 41 close(log) 42 } 43 44 func createRandomLog(n uint64, dif, wrt int, out chan<- *pb.Entry) { 45 srand := rand.NewSource(time.Now().UnixNano()) 46 r := rand.New(srand) 47 48 for i := uint64(0); i < n; i++ { 49 cmd := pb.Entry{ 50 Id: i, 51 Key: int64(r.Intn(dif)), 52 } 53 54 // WRITE operation 55 if cn := r.Intn(100); cn < wrt { 56 cmd.WriteOp = true 57 cmd.Command = generateRandByteSlice() 58 } 59 out <- &cmd 60 } 61 62 // indicates the last command in the log, forcing consumer goroutines to halt 63 out <- &pb.Entry{} 64 } 65 66 func splitIntoWorkers(src <-chan *pb.Entry, wrks ...chan<- *pb.Entry) { 67 for cmd := range src { 68 for _, ch := range wrks { 69 // avoid blocking receive on the sync ch 70 go func(dest chan<- *pb.Entry, c *pb.Entry) { 71 dest <- c 72 }(ch, cmd) 73 } 74 } 75 } 76 77 func runConcTable(log <-chan *pb.Entry, n uint64, mu *sync.Mutex, wg *sync.WaitGroup) { 78 ct := NewConcTable(context.TODO()) 79 var i uint64 80 defer wg.Done() 81 82 start := time.Now() 83 for cmd := range log { 84 if i < n { 85 ct.Log(cmd) 86 i++ 87 88 } else { 89 // finished logging 90 break 91 } 92 } 93 94 // elapsed time to interpret the sequence of commands and construct the tree struct 95 construct := time.Since(start) 96 97 var ( 98 fn, id string 99 out []*pb.Entry 100 101 // elapsed time to recovery the entire log 102 recov time.Duration 103 ) 104 105 // TODO: call reduce procedure for each configuration 106 107 start = time.Now() 108 err := dumpLogIntoFile("./", fn, out) 109 if err != nil { 110 fmt.Println(err.Error()) 111 } 112 dump := time.Since(start) 113 114 mu.Lock() 115 fmt.Println( 116 "\n====================", 117 "\n===", id, 118 "\nRemoved cmds: ", n-uint64(len(out)), 119 "\nConstruction Time: ", construct, 120 "\nCompactation Time: ", recov, 121 "\nInstallation Time:", dump, 122 "\n====================", 123 ) 124 mu.Unlock() 125 } 126 127 func runTraditionalLog(log <-chan *pb.Entry, n uint64, mu *sync.Mutex, wg *sync.WaitGroup) { 128 logfile := make([]*pb.Entry, 0, n) 129 var i uint64 130 defer wg.Done() 131 132 start := time.Now() 133 for cmd := range log { 134 if i < n { 135 logfile = append(logfile, cmd) 136 i++ 137 138 } else { 139 // finished logging 140 break 141 } 142 } 143 144 construct := time.Since(start) 145 fn := "traditionallog-bench.out" 146 147 start = time.Now() 148 err := dumpLogIntoFile("./", fn, logfile) 149 if err != nil { 150 fmt.Println(err.Error()) 151 } 152 dump := time.Since(start) 153 154 mu.Lock() 155 fmt.Println( 156 "\n====================", 157 "\n=== Traditional Log Benchmark", 158 "\nRemoved cmds:", n-uint64(len(logfile)), 159 "\nConstruction Time:", construct, 160 "\nCompactation Time: -", 161 "\nInstallation Time:", dump, 162 "\n====================", 163 ) 164 mu.Unlock() 165 } 166 167 func dumpLogIntoFile(folder, name string, log []*pb.Entry) error { 168 if _, exists := os.Stat(folder); os.IsNotExist(exists) { 169 os.Mkdir(folder, 0744) 170 } 171 172 out, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY, 0744) 173 if err != nil { 174 return err 175 } 176 defer out.Close() 177 178 for _, cmd := range log { 179 _, err = fmt.Fprintf(out, "%v %d %v\n", cmd.WriteOp, cmd.Key, cmd.Command) 180 if err != nil { 181 return err 182 } 183 } 184 return nil 185 }