Skip to content

Instantly share code, notes, and snippets.

@draveness
Last active April 28, 2019 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save draveness/e661f8d020f20d950b4be0cd1f71b1fe to your computer and use it in GitHub Desktop.
Save draveness/e661f8d020f20d950b4be0cd1f71b1fe to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"math/rand"
"sort"
"sync"
"time"
"github.com/RussellLuo/timingwheel"
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
counts := []int{1000, 2000, 3000, 5000, 8000, 10000}
for _, count := range counts {
profileBuiltinTimers(count)
}
}
func profileBuiltinTimers(count int) {
buffers := make(chan time.Duration, count)
var waitGroup sync.WaitGroup
waitGroup.Add(count)
for i := 0; i < count; i++ {
go func() {
defer waitGroup.Done()
start := time.Now()
select {
case <-time.After(10 * time.Millisecond):
end := time.Now()
buffers <- end.Sub(start)
}
}()
}
waitGroup.Wait()
close(buffers)
sum := time.Duration(0)
durations := []time.Duration{}
for time := range buffers {
sum += time
durations = append(durations, time)
}
sort.Slice(durations, func(i, j int) bool {
return durations[i] < durations[j]
})
fmt.Printf("with %d timers\n", count)
fmt.Println("max\t", durations[count-1])
fmt.Println("pct99\t", durations[int(float64(count)*0.99)])
fmt.Println("pct95\t", durations[int(float64(count)*0.95)])
fmt.Println("avg\t", sum/time.Duration(count))
fmt.Println("pct5\t", durations[int(float64(count)*0.05)])
fmt.Println("pct1\t", durations[int(float64(count)*0.01)])
fmt.Println("min\t", durations[0])
}
func profileTimers(count int) {
buffers := make(chan time.Duration, count)
var waitGroup sync.WaitGroup
waitGroup.Add(count)
tws := []*timingwheel.TimingWheel{}
twCount := 1
for i := 0; i < twCount; i++ {
tw := timingwheel.NewTimingWheel(3000*time.Microsecond, 4)
tw.Start()
tws = append(tws, tw)
}
for i := 0; i < count; i++ {
twIndex := rand.Intn(len(tws))
go func() {
defer waitGroup.Done()
start := time.Now()
ch := make(chan int)
tws[twIndex].AfterFunc(10*time.Millisecond, func() {
ch <- 1
})
select {
case <-ch:
end := time.Now()
buffers <- end.Sub(start)
}
}()
}
waitGroup.Wait()
close(buffers)
for _, tw := range tws {
tw.Stop()
}
sum := time.Duration(0)
durations := []time.Duration{}
for time := range buffers {
sum += time
durations = append(durations, time)
}
sort.Slice(durations, func(i, j int) bool {
return durations[i] < durations[j]
})
fmt.Printf("with %d timers\n", count)
fmt.Println("max\t", durations[count-1])
fmt.Println("pct99\t", durations[int(float64(count)*0.99)])
fmt.Println("pct95\t", durations[int(float64(count)*0.95)])
fmt.Println("avg\t", sum/time.Duration(count))
fmt.Println("pct5\t", durations[int(float64(count)*0.05)])
fmt.Println("pct1\t", durations[int(float64(count)*0.01)])
fmt.Println("min\t", durations[0])
}
func profileTimerWithFixQPS(qps int) {
buffer := make(chan struct{}, qps)
tw := timingwheel.NewTimingWheel(3000*time.Microsecond, 10)
tw.Start()
count := 0
fatal := 0
var lock sync.Mutex
for {
count++
buffer <- struct{}{}
go func() {
start := time.Now()
ch := make(chan int)
tw.AfterFunc(10*time.Millisecond, func() {
ch <- 1
})
select {
case <-ch:
timeouts := time.Since(start)
if timeouts > 20*time.Millisecond {
lock.Lock()
fatal++
lock.Unlock()
}
}
fmt.Printf("%d/%d\n", fatal, count)
<-buffer
}()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment