diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go index 929d4a9636..af19274702 100644 --- a/src/pkg/runtime/crash_test.go +++ b/src/pkg/runtime/crash_test.go @@ -14,7 +14,7 @@ import ( "text/template" ) -// testEnv excludes GOGCTRACE from the environment +// testEnv excludes GODEBUG from the environment // to prevent its output from breaking tests that // are trying to parse other command output. func testEnv(cmd *exec.Cmd) *exec.Cmd { @@ -22,7 +22,7 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd { panic("environment already set") } for _, env := range os.Environ() { - if strings.HasPrefix(env, "GOGCTRACE=") { + if strings.HasPrefix(env, "GODEBUG=") { continue } cmd.Env = append(cmd.Env, env) diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go index a7451e6630..950c0be257 100644 --- a/src/pkg/runtime/extern.go +++ b/src/pkg/runtime/extern.go @@ -21,10 +21,11 @@ is GOGC=100. Setting GOGC=off disables the garbage collector entirely. The runtime/debug package's SetGCPercent function allows changing this percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent. -The GOGCTRACE variable controls debug output from the garbage collector. -Setting GOGCTRACE=1 causes the garbage collector to emit a single line to standard +The GODEBUG variable controls debug output from the runtime. GODEBUG value is +a comma-separated list of name=val pairs. Supported names are: +gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard error at each collection, summarizing the amount of memory collected and the -length of the pause. Setting GOGCTRACE=2 emits the same summary but also +length of the pause. Setting gctrace=2 emits the same summary but also repeats each collection. The GOMAXPROCS variable limits the number of operating system threads that diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index c9ac557154..a819135901 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -82,8 +82,6 @@ enum { // uint32 runtime·worldsema = 1; -static int32 gctrace; - typedef struct Obj Obj; struct Obj { @@ -1950,7 +1948,6 @@ static FuncVal runfinqv = {runfinq}; void runtime·gc(int32 force) { - byte *p; struct gc_args a; int32 i; @@ -1978,10 +1975,6 @@ runtime·gc(int32 force) if(gcpercent == GcpercentUnknown) gcpercent = readgogc(); runtime·unlock(&runtime·mheap); - - p = runtime·getenv("GOGCTRACE"); - if(p != nil) - gctrace = runtime·atoi(p); } if(gcpercent < 0) return; @@ -2004,7 +1997,7 @@ runtime·gc(int32 force) // the root set down a bit (g0 stacks are not scanned, and // we don't need to scan gc's internal state). Also an // enabler for copyable stacks. - for(i = 0; i < (gctrace > 1 ? 2 : 1); i++) { + for(i = 0; i < (runtime·debug.gctrace > 1 ? 2 : 1); i++) { if(g == m->g0) { // already on g0 gc(&a); @@ -2068,7 +2061,7 @@ gc(struct gc_args *args) heap0 = 0; obj0 = 0; - if(gctrace) { + if(runtime·debug.gctrace) { updatememstats(nil); heap0 = mstats.heap_alloc; obj0 = mstats.nmalloc - mstats.nfree; @@ -2131,7 +2124,7 @@ gc(struct gc_args *args) if(mstats.debuggc) runtime·printf("pause %D\n", t4-t0); - if(gctrace) { + if(runtime·debug.gctrace) { updatememstats(&stats); heap1 = mstats.heap_alloc; obj1 = mstats.nmalloc - mstats.nfree; diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c index f988fe3f26..e076d89f13 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -441,8 +441,6 @@ runtime·MHeap_Scavenger(void) uint64 tick, now, forcegc, limit; uint32 k; uintptr sumreleased; - byte *env; - bool trace; Note note, *notep; g->issystem = true; @@ -459,11 +457,6 @@ runtime·MHeap_Scavenger(void) else tick = limit/2; - trace = false; - env = runtime·getenv("GOGCTRACE"); - if(env != nil) - trace = runtime·atoi(env) > 0; - h = &runtime·mheap; for(k=0;; k++) { runtime·noteclear(¬e); @@ -484,7 +477,7 @@ runtime·MHeap_Scavenger(void) runtime·entersyscallblock(); runtime·notesleep(¬e); runtime·exitsyscall(); - if(trace) + if(runtime·debug.gctrace > 0) runtime·printf("scvg%d: GC forced\n", k); runtime·lock(h); now = runtime·nanotime(); @@ -492,7 +485,7 @@ runtime·MHeap_Scavenger(void) sumreleased = scavenge(now, limit); runtime·unlock(h); - if(trace) { + if(runtime·debug.gctrace > 0) { if(sumreleased > 0) runtime·printf("scvg%d: %p MB released\n", k, sumreleased>>20); runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n", diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 44892e8540..b93f4911d7 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -132,6 +132,7 @@ runtime·schedinit(void) runtime·goargs(); runtime·goenvs(); + runtime·parsedebugvars(); // Allocate internal symbol table representation now, we need it for GC anyway. runtime·symtabinit(); diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go index 47d34d7ad9..4776ae22da 100644 --- a/src/pkg/runtime/race/race_test.go +++ b/src/pkg/runtime/race/race_test.go @@ -147,7 +147,7 @@ func runTests() ([]byte, error) { // It is required because the tests contain a lot of data races on the same addresses // (the tests are simple and the memory is constantly reused). for _, env := range os.Environ() { - if strings.HasPrefix(env, "GOMAXPROCS=") || strings.HasPrefix(env, "GOGCTRACE=") { + if strings.HasPrefix(env, "GOMAXPROCS=") || strings.HasPrefix(env, "GODEBUG=") { continue } cmd.Env = append(cmd.Env, env) diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index d62408118b..f59a3f4e80 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -365,3 +365,34 @@ runtime∕pprof·runtime_cyclesPerSecond(int64 res) res = runtime·tickspersecond(); FLUSH(&res); } + +DebugVars runtime·debug; + +static struct { + int8* name; + int32* value; +} dbgvar[] = { + {"gctrace", &runtime·debug.gctrace}, +}; + +void +runtime·parsedebugvars(void) +{ + byte *p; + int32 i, n; + + p = runtime·getenv("GODEBUG"); + if(p == nil) + return; + for(;;) { + for(i=0; i