mirror of
https://github.com/golang/go
synced 2024-11-19 20:54:39 -07:00
runtime: write memory profile statistics to the heap dump.
LGTM=rsc R=rsc, khr CC=golang-codereviews https://golang.org/cl/97010043
This commit is contained in:
parent
1c2cc125fb
commit
65c63dc4aa
@ -49,6 +49,8 @@ enum {
|
||||
TagBss = 13,
|
||||
TagDefer = 14,
|
||||
TagPanic = 15,
|
||||
TagMemProf = 16,
|
||||
TagAllocSample = 17,
|
||||
|
||||
TypeInfo_Conservative = 127,
|
||||
};
|
||||
@ -689,6 +691,74 @@ dumpmemstats(void)
|
||||
dumpint(mstats.numgc);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -713,6 +783,7 @@ mdump(G *gp)
|
||||
dumpms();
|
||||
dumproots();
|
||||
dumpmemstats();
|
||||
dumpmemprof();
|
||||
dumpint(TagEOF);
|
||||
flush();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user