Skip to content

Instantly share code, notes, and snippets.

@kurin
Created April 27, 2019 02:39
Show Gist options
  • Save kurin/494f3294ca77d37c63a71b028afbf39a to your computer and use it in GitHub Desktop.
Save kurin/494f3294ca77d37c63a71b028afbf39a to your computer and use it in GitHub Desktop.
Benchmark code
package main
import (
"bytes"
"compress/gzip"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"sync"
"time"
)
var (
W = flag.Int("w", 2, "workers")
Q = flag.Int("q", 10, "queue")
R = flag.Int("r", 4096, "request size")
lifo = false
)
func filename() string {
b := &bytes.Buffer{}
if lifo {
b.WriteString("lifo-")
} else {
b.WriteString("fifo-")
}
fmt.Fprintf(b, "w%dq%dr%d.csv", *W, *Q, *R)
return b.String()
}
func main() {
flag.Parse()
do()
lifo = true
do()
}
func do() {
var q queue
q.max = *Q
q.c = sync.NewCond(&q.mu)
var wg sync.WaitGroup
done := make(chan struct{})
for i := 0; i < *W+1; i++ {
wg.Add(1)
go func() {
defer wg.Done()
q.work(done)
}()
}
fmt.Fprintln(os.Stderr, "workers spun up")
ch := make(chan *request)
go q.spin(ch, done)
var reqs []*request
f, err := os.Create(filename())
if err != nil {
fmt.Println(err)
return
}
for i := 0; i < 100000; i++ {
wasteTime(32)
r := &request{size: int64(*R), create: time.Now(), n: i}
ch <- r
reqs = append(reqs, r)
}
close(ch)
fmt.Fprintln(os.Stderr, "waitin'")
wg.Wait()
fmt.Fprintln(f, "c_time,q_time,work_time")
for _, r := range reqs {
fmt.Fprintf(f, "%d,%d,%d\n", r.enq.Sub(r.create), r.start.Sub(r.enq), r.end.Sub(r.start))
}
fmt.Println(f.Close())
}
type request struct {
n int
size int64
create time.Time
enq time.Time
start time.Time
end time.Time
}
func (q *queue) spin(inc chan *request, done chan struct{}) {
defer q.c.Broadcast()
defer close(done)
for req := range inc {
q.mu.Lock()
if len(q.q) < q.max {
req.enq = time.Now()
q.q = append(q.q, req)
q.c.Broadcast()
}
q.mu.Unlock()
}
}
func (q *queue) work(done chan struct{}) {
for {
q.mu.Lock()
for len(q.q) < 1 {
select {
case <-done:
q.mu.Unlock()
return
default:
q.c.Wait()
}
}
var req *request
if lifo {
req = q.q[len(q.q)-1]
q.q = q.q[:len(q.q)-1]
} else {
req = q.q[0]
q.q = q.q[1:]
}
q.mu.Unlock()
req.start = time.Now()
wasteTime(req.size)
req.end = time.Now()
if req.n%100 == 0 {
fmt.Println(req.n)
}
}
}
type queue struct {
mu sync.Mutex
c *sync.Cond
q []*request
max int
}
func wasteTime(n int64) error {
f, err := os.Open("/dev/urandom")
if err != nil {
return err
}
defer f.Close()
w := gzip.NewWriter(ioutil.Discard)
if _, err := io.Copy(w, io.LimitReader(f, n)); err != nil {
return err
}
return w.Close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment