package main import ( "container/list" "crypto/md5" "fmt" "hash" "log" "net/http" _ "net/http/pprof" "time" "github.com/petermattis/goid" ) const goroutines = 512 const goroutinesRunnable = 8 const rate = 30000 // per second const wait = time.Second / rate const goroutineRuntime = goroutinesRunnable * wait const allocsPerLoop = 20 const allocSize = 2048 const timePerAlloc = int(goroutineRuntime) / allocsPerLoop const timePerHash = 2 * allocSize // roughly const hashesPerAlloc = timePerAlloc / timePerHash const ballastSize = 1 << 30 // 1GB var ballast = make([]byte, ballastSize) var ptrBallast = func() list.List { var l list.List for i := 0; i < ballastSize; i += 1024 { l.PushBack(&ballast[i]) } return l }() type g struct { id int64 run chan struct{} hash hash.Hash } func (g *g) runLoop() { g.id = goid.Get() for { <-g.run g.runOnce() } } func (g *g) runOnce() { start := time.Now() var list list.List for i := 0; i < allocsPerLoop; i++ { alloc := make([]byte, allocSize) for j := 0; j < hashesPerAlloc; j++ { g.hash.Write(alloc) } list.PushBack(alloc) } dur := time.Since(start) if dur > 40*goroutineRuntime { fmt.Printf("%d: slow run: %v\n", g.id, dur) } } func main() { go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }() gs := make([]g, goroutines) for i := range gs { gs[i] = g{ run: make(chan struct{}, 1), hash: md5.New(), } go gs[i].runLoop() } for { for i := range gs { select { case gs[i].run <- struct{}{}: default: } time.Sleep(wait) } } }