mirror of https://github.com/golang/go.git
runtime: output how long goroutines are blocked
Example of output:
goroutine 4 [sleep for 3 min]:
time.Sleep(0x34630b8a000)
src/pkg/runtime/time.goc:31 +0x31
main.func·002()
block.go:16 +0x2c
created by main.main
block.go:17 +0x33
Full program and output are here:
http://play.golang.org/p/NEZdADI3Td
Fixes #6809.
R=golang-codereviews, khr, kamil.kisiel, bradfitz, rsc
CC=golang-codereviews
https://golang.org/cl/50420043
This commit is contained in:
parent
4722b1cbd3
commit
c0b9e6218c
|
|
@ -1,4 +1,5 @@
|
||||||
cmd/gofmt: remove -tabwidth and -tabs flags (CL 52170043)
|
cmd/gofmt: remove -tabwidth and -tabs flags (CL 52170043)
|
||||||
liblink: pull linker i/o into separate liblink C library (CL 35790044)
|
liblink: pull linker i/o into separate liblink C library (CL 35790044)
|
||||||
misc/dist: renamed misc/makerelease (CL 39920043)
|
misc/dist: renamed misc/makerelease (CL 39920043)
|
||||||
|
runtime: output how long goroutines are blocked (CL 50420043)
|
||||||
syscall: add NewCallbackCDecl to use for windows callbacks (CL 36180044)
|
syscall: add NewCallbackCDecl to use for windows callbacks (CL 36180044)
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ static struct {
|
||||||
uint64 empty; // lock-free list of empty blocks
|
uint64 empty; // lock-free list of empty blocks
|
||||||
byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
|
byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
|
||||||
uint32 nproc;
|
uint32 nproc;
|
||||||
|
int64 tstart;
|
||||||
volatile uint32 nwait;
|
volatile uint32 nwait;
|
||||||
volatile uint32 ndone;
|
volatile uint32 ndone;
|
||||||
volatile uint32 debugmarkdone;
|
volatile uint32 debugmarkdone;
|
||||||
|
|
@ -1675,6 +1676,11 @@ addroots(void)
|
||||||
addstackroots(gp);
|
addstackroots(gp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember when we've first observed the G blocked
|
||||||
|
// needed only to output in traceback
|
||||||
|
if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0)
|
||||||
|
gp->waitsince = work.tstart;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(fb=allfin; fb; fb=fb->alllink)
|
for(fb=allfin; fb; fb=fb->alllink)
|
||||||
|
|
@ -2230,6 +2236,7 @@ gc(struct gc_args *args)
|
||||||
Eface eface;
|
Eface eface;
|
||||||
|
|
||||||
t0 = args->start_time;
|
t0 = args->start_time;
|
||||||
|
work.tstart = args->start_time;
|
||||||
|
|
||||||
if(CollectStats)
|
if(CollectStats)
|
||||||
runtime·memclr((byte*)&gcstats, sizeof(gcstats));
|
runtime·memclr((byte*)&gcstats, sizeof(gcstats));
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,7 @@ void
|
||||||
runtime·goroutineheader(G *gp)
|
runtime·goroutineheader(G *gp)
|
||||||
{
|
{
|
||||||
int8 *status;
|
int8 *status;
|
||||||
|
int64 waitfor;
|
||||||
|
|
||||||
switch(gp->status) {
|
switch(gp->status) {
|
||||||
case Gidle:
|
case Gidle:
|
||||||
|
|
@ -261,7 +262,16 @@ runtime·goroutineheader(G *gp)
|
||||||
status = "???";
|
status = "???";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// approx time the G is blocked, in minutes
|
||||||
|
waitfor = 0;
|
||||||
|
if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0)
|
||||||
|
waitfor = (runtime·nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
|
||||||
|
|
||||||
|
if(waitfor < 1)
|
||||||
runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
|
runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
|
||||||
|
else
|
||||||
|
runtime·printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1112,6 +1122,7 @@ execute(G *gp)
|
||||||
runtime·throw("execute: bad g status");
|
runtime·throw("execute: bad g status");
|
||||||
}
|
}
|
||||||
gp->status = Grunning;
|
gp->status = Grunning;
|
||||||
|
gp->waitsince = 0;
|
||||||
gp->preempt = false;
|
gp->preempt = false;
|
||||||
gp->stackguard0 = gp->stackguard;
|
gp->stackguard0 = gp->stackguard;
|
||||||
m->p->schedtick++;
|
m->p->schedtick++;
|
||||||
|
|
@ -1535,6 +1546,7 @@ runtime·exitsyscall(void)
|
||||||
if(g->isbackground) // do not consider blocked scavenger for deadlock detection
|
if(g->isbackground) // do not consider blocked scavenger for deadlock detection
|
||||||
incidlelocked(-1);
|
incidlelocked(-1);
|
||||||
|
|
||||||
|
g->waitsince = 0;
|
||||||
if(exitsyscallfast()) {
|
if(exitsyscallfast()) {
|
||||||
// There's a cpu for us, so we can run.
|
// There's a cpu for us, so we can run.
|
||||||
m->p->syscalltick++;
|
m->p->syscalltick++;
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,7 @@ struct G
|
||||||
void* param; // passed parameter on wakeup
|
void* param; // passed parameter on wakeup
|
||||||
int16 status;
|
int16 status;
|
||||||
int64 goid;
|
int64 goid;
|
||||||
|
int64 waitsince; // approx time when the G become blocked
|
||||||
int8* waitreason; // if status==Gwaiting
|
int8* waitreason; // if status==Gwaiting
|
||||||
G* schedlink;
|
G* schedlink;
|
||||||
bool ispanic;
|
bool ispanic;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue