aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2014-07-17 21:51:03 +0400
committerDmitriy Vyukov <dvyukov@google.com>2014-07-17 21:51:03 +0400
commit92c1e720401e07a97670c92b0ac208da8cc4988c (patch)
tree64781ae99b66c8fe00f6199e350cded13edf8fc8 /src/pkg/runtime
parentdc84eca75eab04ec1a0c454ccf135ee9da10951e (diff)
downloadgo-92c1e720401e07a97670c92b0ac208da8cc4988c.tar.xz
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
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/proc.c33
1 files changed, 15 insertions, 18 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 0b75415aca..a88d39dc95 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -47,6 +47,7 @@ struct Sched {
// Global cache of dead G's.
Lock gflock;
G* gfree;
+ int32 ngfree;
uint32 gcwaiting; // gc is waiting to run
int32 stopwait;
@@ -1964,6 +1965,7 @@ gfput(P *p, G *gp)
p->gfree = gp->schedlink;
gp->schedlink = runtime·sched.gfree;
runtime·sched.gfree = gp;
+ runtime·sched.ngfree++;
}
runtime·unlock(&runtime·sched.gflock);
}
@@ -1981,10 +1983,11 @@ retry:
gp = p->gfree;
if(gp == nil && runtime·sched.gfree) {
runtime·lock(&runtime·sched.gflock);
- while(p->gfreecnt < 32 && runtime·sched.gfree) {
+ while(p->gfreecnt < 32 && runtime·sched.gfree != nil) {
p->gfreecnt++;
gp = runtime·sched.gfree;
runtime·sched.gfree = gp->schedlink;
+ runtime·sched.ngfree--;
gp->schedlink = p->gfree;
p->gfree = gp;
}
@@ -2022,12 +2025,13 @@ gfpurge(P *p)
G *gp;
runtime·lock(&runtime·sched.gflock);
- while(p->gfreecnt) {
+ while(p->gfreecnt != 0) {
p->gfreecnt--;
gp = p->gfree;
p->gfree = gp->schedlink;
gp->schedlink = runtime·sched.gfree;
runtime·sched.gfree = gp;
+ runtime·sched.ngfree++;
}
runtime·unlock(&runtime·sched.gflock);
}
@@ -2136,23 +2140,16 @@ runtime·lockedOSThread(void)
int32
runtime·gcount(void)
{
- G *gp;
- int32 n, s;
- uintptr i;
+ P *p, **pp;
+ int32 n;
- n = 0;
- runtime·lock(&allglock);
- // TODO(dvyukov): runtime.NumGoroutine() is O(N).
- // We do not want to increment/decrement centralized counter in newproc/goexit,
- // just to make runtime.NumGoroutine() faster.
- // Compromise solution is to introduce per-P counters of active goroutines.
- for(i = 0; i < runtime·allglen; i++) {
- gp = runtime·allg[i];
- s = gp->status;
- if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
- n++;
- }
- runtime·unlock(&allglock);
+ n = runtime·allglen - runtime·sched.ngfree;
+ for(pp=runtime·allp; p=*pp; pp++)
+ n -= p->gfreecnt;
+ // All these variables can be changed concurrently, so the result can be inconsistent.
+ // But at least the current goroutine is running.
+ if(n < 1)
+ n = 1;
return n;
}