1
0
mirror of https://github.com/golang/go synced 2024-11-12 10:30:23 -07:00

runtime: make NumGoroutines faster

Resolves TODO for not walking all goroutines in NumGoroutines.

LGTM=khr
R=golang-codereviews, khr
CC=golang-codereviews, rsc
https://golang.org/cl/107290044
This commit is contained in:
Dmitriy Vyukov 2014-07-17 21:51:03 +04:00
parent dc84eca75e
commit 92c1e72040

View File

@ -47,6 +47,7 @@ struct Sched {
// Global cache of dead G's. // Global cache of dead G's.
Lock gflock; Lock gflock;
G* gfree; G* gfree;
int32 ngfree;
uint32 gcwaiting; // gc is waiting to run uint32 gcwaiting; // gc is waiting to run
int32 stopwait; int32 stopwait;
@ -1964,6 +1965,7 @@ gfput(P *p, G *gp)
p->gfree = gp->schedlink; p->gfree = gp->schedlink;
gp->schedlink = runtime·sched.gfree; gp->schedlink = runtime·sched.gfree;
runtime·sched.gfree = gp; runtime·sched.gfree = gp;
runtime·sched.ngfree++;
} }
runtime·unlock(&runtime·sched.gflock); runtime·unlock(&runtime·sched.gflock);
} }
@ -1981,10 +1983,11 @@ retry:
gp = p->gfree; gp = p->gfree;
if(gp == nil && runtime·sched.gfree) { if(gp == nil && runtime·sched.gfree) {
runtime·lock(&runtime·sched.gflock); runtime·lock(&runtime·sched.gflock);
while(p->gfreecnt < 32 && runtime·sched.gfree) { while(p->gfreecnt < 32 && runtime·sched.gfree != nil) {
p->gfreecnt++; p->gfreecnt++;
gp = runtime·sched.gfree; gp = runtime·sched.gfree;
runtime·sched.gfree = gp->schedlink; runtime·sched.gfree = gp->schedlink;
runtime·sched.ngfree--;
gp->schedlink = p->gfree; gp->schedlink = p->gfree;
p->gfree = gp; p->gfree = gp;
} }
@ -2022,12 +2025,13 @@ gfpurge(P *p)
G *gp; G *gp;
runtime·lock(&runtime·sched.gflock); runtime·lock(&runtime·sched.gflock);
while(p->gfreecnt) { while(p->gfreecnt != 0) {
p->gfreecnt--; p->gfreecnt--;
gp = p->gfree; gp = p->gfree;
p->gfree = gp->schedlink; p->gfree = gp->schedlink;
gp->schedlink = runtime·sched.gfree; gp->schedlink = runtime·sched.gfree;
runtime·sched.gfree = gp; runtime·sched.gfree = gp;
runtime·sched.ngfree++;
} }
runtime·unlock(&runtime·sched.gflock); runtime·unlock(&runtime·sched.gflock);
} }
@ -2136,23 +2140,16 @@ runtime·lockedOSThread(void)
int32 int32
runtime·gcount(void) runtime·gcount(void)
{ {
G *gp; P *p, **pp;
int32 n, s; int32 n;
uintptr i;
n = 0; n = runtime·allglen - runtime·sched.ngfree;
runtime·lock(&allglock); for(pp=runtime·allp; p=*pp; pp++)
// TODO(dvyukov): runtime.NumGoroutine() is O(N). n -= p->gfreecnt;
// We do not want to increment/decrement centralized counter in newproc/goexit, // All these variables can be changed concurrently, so the result can be inconsistent.
// just to make runtime.NumGoroutine() faster. // But at least the current goroutine is running.
// Compromise solution is to introduce per-P counters of active goroutines. if(n < 1)
for(i = 0; i < runtime·allglen; i++) { n = 1;
gp = runtime·allg[i];
s = gp->status;
if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
n++;
}
runtime·unlock(&allglock);
return n; return n;
} }