aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-05-08 08:35:49 -0700
committerKeith Randall <khr@golang.org>2014-05-08 08:35:49 -0700
commit65c63dc4aabba3ecd320427fb20bc1cdbe0d2a3d (patch)
tree8773cd3a19ea070f92bbfc3d6a31c818ae20c74e /src/pkg/runtime
parent1c2cc125fb2baad78167ee543f1d96aea9135734 (diff)
downloadgo-65c63dc4aabba3ecd320427fb20bc1cdbe0d2a3d.tar.xz
runtime: write memory profile statistics to the heap dump.
LGTM=rsc R=rsc, khr CC=golang-codereviews https://golang.org/cl/97010043
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/heapdump.c71
-rw-r--r--src/pkg/runtime/malloc.h1
-rw-r--r--src/pkg/runtime/mprof.goc12
3 files changed, 84 insertions, 0 deletions
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
index 9132e2c186..42d1601aa1 100644
--- a/src/pkg/runtime/heapdump.c
+++ b/src/pkg/runtime/heapdump.c
@@ -49,6 +49,8 @@ enum {
TagBss = 13,
TagDefer = 14,
TagPanic = 15,
+ TagMemProf = 16,
+ TagAllocSample = 17,
TypeInfo_Conservative = 127,
};
@@ -690,6 +692,74 @@ dumpmemstats(void)
}
static void
+dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
+{
+ uintptr i, pc;
+ Func *f;
+ byte buf[20];
+ String file;
+ int32 line;
+
+ dumpint(TagMemProf);
+ dumpint((uintptr)b);
+ dumpint(size);
+ dumpint(nstk);
+ for(i = 0; i < nstk; i++) {
+ pc = stk[i];
+ f = runtime·findfunc(pc);
+ if(f == nil) {
+ runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
+ dumpcstr((int8*)buf);
+ dumpcstr("?");
+ dumpint(0);
+ } else {
+ dumpcstr(runtime·funcname(f));
+ // TODO: Why do we need to back up to a call instruction here?
+ // Maybe profiler should do this.
+ if(i > 0 && pc > f->entry) {
+ if(thechar == '6' || thechar == '8')
+ pc--;
+ else
+ pc -= 4; // arm, etc
+ }
+ line = runtime·funcline(f, pc, &file);
+ dumpstr(file);
+ dumpint(line);
+ }
+ }
+ dumpint(allocs);
+ dumpint(frees);
+}
+
+static void
+dumpmemprof(void)
+{
+ MSpan *s, **allspans;
+ uint32 spanidx;
+ Special *sp;
+ SpecialProfile *spp;
+ byte *p;
+
+ runtime·iterate_memprof(dumpmemprof_callback);
+
+ allspans = runtime·mheap.allspans;
+ for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+ s = allspans[spanidx];
+ if(s->state != MSpanInUse)
+ continue;
+ for(sp = s->specials; sp != nil; sp = sp->next) {
+ if(sp->kind != KindSpecialProfile)
+ continue;
+ spp = (SpecialProfile*)sp;
+ p = (byte*)((s->start << PageShift) + spp->offset);
+ dumpint(TagAllocSample);
+ dumpint((uintptr)p);
+ dumpint((uintptr)spp->b);
+ }
+ }
+}
+
+static void
mdump(G *gp)
{
byte *hdr;
@@ -713,6 +783,7 @@ mdump(G *gp)
dumpms();
dumproots();
dumpmemstats();
+ dumpmemprof();
dumpint(TagEOF);
flush();
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index dbea7ad135..798c130ad5 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -570,6 +570,7 @@ enum
void runtime·MProf_Malloc(void*, uintptr);
void runtime·MProf_Free(Bucket*, uintptr, bool);
void runtime·MProf_GC(void);
+void runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr));
int32 runtime·gcprocs(void);
void runtime·helpgc(int32 nproc);
void runtime·gchelper(void);
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index a1659a7b42..9c23a16f88 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -309,6 +309,18 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
runtime·unlock(&proflock);
}
+void
+runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr))
+{
+ Bucket *b;
+
+ runtime·lock(&proflock);
+ for(b=mbuckets; b; b=b->allnext) {
+ callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
+ }
+ runtime·unlock(&proflock);
+}
+
// Must match BlockProfileRecord in debug.go.
typedef struct BRecord BRecord;
struct BRecord {