diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2013-07-19 01:22:26 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2013-07-19 01:22:26 +0400 |
| commit | bc31bcccd3b94ec8dd324e523c4c7ae9180b937f (patch) | |
| tree | ae43ea1cd52087133568592922685845539505ba /src/pkg/runtime/proc.c | |
| parent | 58f12ffd79df8ae369afa7ec60ee26d72ce2d843 (diff) | |
| download | go-bc31bcccd3b94ec8dd324e523c4c7ae9180b937f.tar.xz | |
runtime: preempt long-running goroutines
If a goroutine runs for more than 10ms, preempt it.
Update #543.
R=rsc
CC=golang-dev
https://golang.org/cl/10796043
Diffstat (limited to 'src/pkg/runtime/proc.c')
| -rw-r--r-- | src/pkg/runtime/proc.c | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 331d382476..fe32f2c28b 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -94,7 +94,7 @@ static void wakep(void); static void stoplockedm(void); static void startlockedm(G*); static void sysmon(void); -static uint32 retake(uint32*); +static uint32 retake(int64); static void inclocked(int32); static void checkdead(void); static void exitsyscall0(G*); @@ -2071,7 +2071,6 @@ sysmon(void) uint32 idle, delay; int64 now, lastpoll; G *gp; - uint32 ticks[MaxGomaxprocs]; idle = 0; // how many cycles in succession we had not wokeup somebody delay = 0; @@ -2103,19 +2102,29 @@ sysmon(void) injectglist(gp); } // retake P's blocked in syscalls - if(retake(ticks)) + // and preempt long running G's + if(retake(now)) idle = 0; else idle++; } } +typedef struct Pdesc Pdesc; +struct Pdesc +{ + uint32 tick; + int64 when; +}; +static Pdesc pdesc[MaxGomaxprocs]; + static uint32 -retake(uint32 *ticks) +retake(int64 now) { uint32 i, s, n; int64 t; P *p; + Pdesc *pd; n = 0; for(i = 0; i < runtime·gomaxprocs; i++) { @@ -2123,24 +2132,34 @@ retake(uint32 *ticks) if(p==nil) continue; t = p->tick; - if(ticks[i] != t) { - ticks[i] = t; + pd = &pdesc[i]; + if(pd->tick != t) { + pd->tick = t; + pd->when = now; continue; } s = p->status; - if(s != Psyscall) - continue; - if(p->runqhead == p->runqtail && runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0) // TODO: fast atomic - continue; - // Need to increment number of locked M's before the CAS. - // Otherwise the M from which we retake can exit the syscall, - // increment nmidle and report deadlock. - inclocked(-1); - if(runtime·cas(&p->status, s, Pidle)) { - n++; - handoffp(p); + if(s == Psyscall) { + // Retake P from syscall if it's there for more than 1 sysmon tick (20us). + // But only if there is other work to do. + if(p->runqhead == p->runqtail && + runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0) + continue; + // Need to increment number of locked M's before the CAS. + // Otherwise the M from which we retake can exit the syscall, + // increment nmidle and report deadlock. + inclocked(-1); + if(runtime·cas(&p->status, s, Pidle)) { + n++; + handoffp(p); + } + inclocked(1); + } else if(s == Prunning) { + // Preempt G if it's running for more than 10ms. + if(pd->when + 10*1000*1000 > now) + continue; + preemptone(p); } - inclocked(1); } return n; } |
