diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-01-22 10:34:36 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-01-22 10:34:36 +0400 |
| commit | 98b50b89a8002e1a40f28d1851d0223d424825f6 (patch) | |
| tree | 112653f6cfbd1bba5d79c5b47d4cf16cae178226 /src/pkg/runtime/proc.c | |
| parent | 8a3c587dc1a5f7a9cd87b764b74e28a57935ab40 (diff) | |
| download | go-98b50b89a8002e1a40f28d1851d0223d424825f6.tar.xz | |
runtime: allocate goroutine ids in batches
Helps reduce contention on sched.goidgen.
benchmark old ns/op new ns/op delta
BenchmarkCreateGoroutines-16 259 237 -8.49%
BenchmarkCreateGoroutinesParallel-16 127 43 -66.06%
R=golang-codereviews, dave, bradfitz, khr
CC=golang-codereviews, rsc
https://golang.org/cl/46970043
Diffstat (limited to 'src/pkg/runtime/proc.c')
| -rw-r--r-- | src/pkg/runtime/proc.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 92d6f27da3..9eb4ad9f95 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -58,9 +58,16 @@ struct Sched { int32 profilehz; // cpu profiling rate }; -// The max value of GOMAXPROCS. -// There are no fundamental restrictions on the value. -enum { MaxGomaxprocs = 1<<8 }; +enum +{ + // The max value of GOMAXPROCS. + // There are no fundamental restrictions on the value. + MaxGomaxprocs = 1<<8, + + // Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once. + // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. + GoidCacheBatch = 16, +}; Sched runtime·sched; int32 runtime·gomaxprocs; @@ -1752,6 +1759,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp { byte *sp; G *newg; + P *p; int32 siz; //runtime·printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret); @@ -1766,7 +1774,8 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp if(siz > StackMin - 1024) runtime·throw("runtime.newproc: function arguments too large for new goroutine"); - if((newg = gfget(m->p)) != nil) { + p = m->p; + if((newg = gfget(p)) != nil) { if(newg->stackguard - StackGuard != newg->stack0) runtime·throw("invalid stack in newg"); } else { @@ -1790,11 +1799,15 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp runtime·gostartcallfn(&newg->sched, fn); newg->gopc = (uintptr)callerpc; newg->status = Grunnable; - newg->goid = runtime·xadd64(&runtime·sched.goidgen, 1); + if(p->goidcache == p->goidcacheend) { + p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch); + p->goidcacheend = p->goidcache + GoidCacheBatch; + } + newg->goid = p->goidcache++; newg->panicwrap = 0; if(raceenabled) newg->racectx = runtime·racegostart((void*)callerpc); - runqput(m->p, newg); + runqput(p, newg); if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main) // TODO: fast atomic wakep(); |
