aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.1/libgo/runtime/mprof.goc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.1/libgo/runtime/mprof.goc')
-rw-r--r--gcc-4.8.1/libgo/runtime/mprof.goc533
1 files changed, 0 insertions, 533 deletions
diff --git a/gcc-4.8.1/libgo/runtime/mprof.goc b/gcc-4.8.1/libgo/runtime/mprof.goc
deleted file mode 100644
index c1b09bea7..000000000
--- a/gcc-4.8.1/libgo/runtime/mprof.goc
+++ /dev/null
@@ -1,533 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Malloc profiling.
-// Patterned after tcmalloc's algorithms; shorter code.
-
-package runtime
-#include "runtime.h"
-#include "arch.h"
-#include "malloc.h"
-#include "defs.h"
-#include "go-type.h"
-#include "go-string.h"
-
-// NOTE(rsc): Everything here could use cas if contention became an issue.
-static Lock proflock;
-
-enum { MProf, BProf }; // profile types
-
-// Per-call-stack profiling information.
-// Lookup by hashing call stack into a linked-list hash table.
-typedef struct Bucket Bucket;
-struct Bucket
-{
- Bucket *next; // next in hash list
- Bucket *allnext; // next in list of all mbuckets/bbuckets
- int32 typ;
- union
- {
- struct // typ == MProf
- {
- uintptr allocs;
- uintptr frees;
- uintptr alloc_bytes;
- uintptr free_bytes;
- uintptr recent_allocs; // since last gc
- uintptr recent_frees;
- uintptr recent_alloc_bytes;
- uintptr recent_free_bytes;
- };
- struct // typ == BProf
- {
- int64 count;
- int64 cycles;
- };
- };
- uintptr hash;
- uintptr nstk;
- Location stk[1];
-};
-enum {
- BuckHashSize = 179999,
-};
-static Bucket **buckhash;
-static Bucket *mbuckets; // memory profile buckets
-static Bucket *bbuckets; // blocking profile buckets
-static uintptr bucketmem;
-
-// Return the bucket for stk[0:nstk], allocating new bucket if needed.
-static Bucket*
-stkbucket(int32 typ, Location *stk, int32 nstk, bool alloc)
-{
- int32 i, j;
- uintptr h;
- Bucket *b;
-
- if(buckhash == nil) {
- buckhash = runtime_SysAlloc(BuckHashSize*sizeof buckhash[0]);
- mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
- }
-
- // Hash stack.
- h = 0;
- for(i=0; i<nstk; i++) {
- h += stk[i].pc;
- h += h<<10;
- h ^= h>>6;
- }
- h += h<<3;
- h ^= h>>11;
-
- i = h%BuckHashSize;
- for(b = buckhash[i]; b; b=b->next) {
- if(b->typ == typ && b->hash == h && b->nstk == (uintptr)nstk) {
- for(j = 0; j < nstk; j++) {
- if(b->stk[j].pc != stk[j].pc ||
- b->stk[j].lineno != stk[j].lineno ||
- !__go_strings_equal(b->stk[j].filename, stk[j].filename))
- break;
- }
- if (j == nstk)
- return b;
- }
- }
-
- if(!alloc)
- return nil;
-
- b = runtime_mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
- bucketmem += sizeof *b + nstk*sizeof stk[0];
- runtime_memmove(b->stk, stk, nstk*sizeof stk[0]);
- b->typ = typ;
- b->hash = h;
- b->nstk = nstk;
- b->next = buckhash[i];
- buckhash[i] = b;
- if(typ == MProf) {
- b->allnext = mbuckets;
- mbuckets = b;
- } else {
- b->allnext = bbuckets;
- bbuckets = b;
- }
- return b;
-}
-
-// Record that a gc just happened: all the 'recent' statistics are now real.
-void
-runtime_MProf_GC(void)
-{
- Bucket *b;
-
- runtime_lock(&proflock);
- for(b=mbuckets; b; b=b->allnext) {
- b->allocs += b->recent_allocs;
- b->frees += b->recent_frees;
- b->alloc_bytes += b->recent_alloc_bytes;
- b->free_bytes += b->recent_free_bytes;
- b->recent_allocs = 0;
- b->recent_frees = 0;
- b->recent_alloc_bytes = 0;
- b->recent_free_bytes = 0;
- }
- runtime_unlock(&proflock);
-}
-
-// Map from pointer to Bucket* that allocated it.
-// Three levels:
-// Linked-list hash table for top N-AddrHashShift bits.
-// Array index for next AddrDenseBits bits.
-// Linked list for next AddrHashShift-AddrDenseBits bits.
-// This is more efficient than using a general map,
-// because of the typical clustering of the pointer keys.
-
-typedef struct AddrHash AddrHash;
-typedef struct AddrEntry AddrEntry;
-
-enum {
- AddrHashBits = 12, // good for 4GB of used address space
- AddrHashShift = 20, // each AddrHash knows about 1MB of address space
- AddrDenseBits = 8, // good for a profiling rate of 4096 bytes
-};
-
-struct AddrHash
-{
- AddrHash *next; // next in top-level hash table linked list
- uintptr addr; // addr>>20
- AddrEntry *dense[1<<AddrDenseBits];
-};
-
-struct AddrEntry
-{
- AddrEntry *next; // next in bottom-level linked list
- uint32 addr;
- Bucket *b;
-};
-
-static AddrHash *addrhash[1<<AddrHashBits];
-static AddrEntry *addrfree;
-static uintptr addrmem;
-
-// Multiplicative hash function:
-// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
-// This is a good multiplier as suggested in CLR, Knuth. The hash
-// value is taken to be the top AddrHashBits bits of the bottom 32 bits
-// of the multiplied value.
-enum {
- HashMultiplier = 2654435769U
-};
-
-// Set the bucket associated with addr to b.
-static void
-setaddrbucket(uintptr addr, Bucket *b)
-{
- int32 i;
- uint32 h;
- AddrHash *ah;
- AddrEntry *e;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
-
- ah = runtime_mallocgc(sizeof *ah, FlagNoProfiling, 0, 1);
- addrmem += sizeof *ah;
- ah->next = addrhash[h];
- ah->addr = addr>>AddrHashShift;
- addrhash[h] = ah;
-
-found:
- if((e = addrfree) == nil) {
- e = runtime_mallocgc(64*sizeof *e, FlagNoProfiling, 0, 0);
- addrmem += 64*sizeof *e;
- for(i=0; i+1<64; i++)
- e[i].next = &e[i+1];
- e[63].next = nil;
- }
- addrfree = e->next;
- e->addr = (uint32)~(addr & ((1<<AddrHashShift)-1));
- e->b = b;
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- e->next = ah->dense[h];
- ah->dense[h] = e;
-}
-
-// Get the bucket associated with addr and clear the association.
-static Bucket*
-getaddrbucket(uintptr addr)
-{
- uint32 h;
- AddrHash *ah;
- AddrEntry *e, **l;
- Bucket *b;
-
- h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
- for(ah=addrhash[h]; ah; ah=ah->next)
- if(ah->addr == (addr>>AddrHashShift))
- goto found;
- return nil;
-
-found:
- h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1); // entry in dense is top 8 bits of low 20.
- for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
- if(e->addr == (uint32)~(addr & ((1<<AddrHashShift)-1))) {
- *l = e->next;
- b = e->b;
- e->next = addrfree;
- addrfree = e;
- return b;
- }
- }
- return nil;
-}
-
-// Called by malloc to record a profiled block.
-void
-runtime_MProf_Malloc(void *p, uintptr size)
-{
- M *m;
- int32 nstk;
- Location stk[32];
- Bucket *b;
-
- m = runtime_m();
- if(m->nomemprof > 0)
- return;
-
- m->nomemprof++;
- nstk = runtime_callers(1, stk, 32);
- runtime_lock(&proflock);
- b = stkbucket(MProf, stk, nstk, true);
- b->recent_allocs++;
- b->recent_alloc_bytes += size;
- setaddrbucket((uintptr)p, b);
- runtime_unlock(&proflock);
- m = runtime_m();
- m->nomemprof--;
-}
-
-// Called when freeing a profiled block.
-void
-runtime_MProf_Free(void *p, uintptr size)
-{
- M *m;
- Bucket *b;
-
- m = runtime_m();
- if(m->nomemprof > 0)
- return;
-
- m->nomemprof++;
- runtime_lock(&proflock);
- b = getaddrbucket((uintptr)p);
- if(b != nil) {
- b->recent_frees++;
- b->recent_free_bytes += size;
- }
- runtime_unlock(&proflock);
- m = runtime_m();
- m->nomemprof--;
-}
-
-int64 runtime_blockprofilerate; // in CPU ticks
-
-void runtime_SetBlockProfileRate(intgo) __asm__ (GOSYM_PREFIX "runtime.SetBlockProfileRate");
-
-void
-runtime_SetBlockProfileRate(intgo rate)
-{
- runtime_atomicstore64((uint64*)&runtime_blockprofilerate, rate * runtime_tickspersecond() / (1000*1000*1000));
-}
-
-void
-runtime_blockevent(int64 cycles, int32 skip)
-{
- int32 nstk;
- int64 rate;
- Location stk[32];
- Bucket *b;
-
- if(cycles <= 0)
- return;
- rate = runtime_atomicload64((uint64*)&runtime_blockprofilerate);
- if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
- return;
-
- nstk = runtime_callers(skip, stk, 32);
- runtime_lock(&proflock);
- b = stkbucket(BProf, stk, nstk, true);
- b->count++;
- b->cycles += cycles;
- runtime_unlock(&proflock);
-}
-
-// Go interface to profile data. (Declared in debug.go)
-
-// Must match MemProfileRecord in debug.go.
-typedef struct Record Record;
-struct Record {
- int64 alloc_bytes, free_bytes;
- int64 alloc_objects, free_objects;
- uintptr stk[32];
-};
-
-// Write b's data to r.
-static void
-record(Record *r, Bucket *b)
-{
- uint32 i;
-
- r->alloc_bytes = b->alloc_bytes;
- r->free_bytes = b->free_bytes;
- r->alloc_objects = b->allocs;
- r->free_objects = b->frees;
- for(i=0; i<b->nstk && i<nelem(r->stk); i++)
- r->stk[i] = b->stk[i].pc;
- for(; i<nelem(r->stk); i++)
- r->stk[i] = 0;
-}
-
-func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
- Bucket *b;
- Record *r;
-
- runtime_lock(&proflock);
- n = 0;
- for(b=mbuckets; b; b=b->allnext)
- if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
- n++;
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (Record*)p.__values;
- for(b=mbuckets; b; b=b->allnext)
- if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
- record(r++, b);
- }
- runtime_unlock(&proflock);
-}
-
-void
-runtime_MProf_Mark(void (*addroot)(Obj))
-{
- // buckhash is not allocated via mallocgc.
- addroot((Obj){(byte*)&mbuckets, sizeof mbuckets, 0});
- addroot((Obj){(byte*)&bbuckets, sizeof bbuckets, 0});
- addroot((Obj){(byte*)&addrhash, sizeof addrhash, 0});
- addroot((Obj){(byte*)&addrfree, sizeof addrfree, 0});
-}
-
-// Must match BlockProfileRecord in debug.go.
-typedef struct BRecord BRecord;
-struct BRecord {
- int64 count;
- int64 cycles;
- uintptr stk[32];
-};
-
-func BlockProfile(p Slice) (n int, ok bool) {
- Bucket *b;
- BRecord *r;
- int32 i;
-
- runtime_lock(&proflock);
- n = 0;
- for(b=bbuckets; b; b=b->allnext)
- n++;
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (BRecord*)p.__values;
- for(b=bbuckets; b; b=b->allnext, r++) {
- r->count = b->count;
- r->cycles = b->cycles;
- for(i=0; (uintptr)i<b->nstk && (uintptr)i<nelem(r->stk); i++)
- r->stk[i] = b->stk[i].pc;
- for(; (uintptr)i<nelem(r->stk); i++)
- r->stk[i] = 0;
- }
- }
- runtime_unlock(&proflock);
-}
-
-// Must match StackRecord in debug.go.
-typedef struct TRecord TRecord;
-struct TRecord {
- uintptr stk[32];
-};
-
-func ThreadCreateProfile(p Slice) (n int, ok bool) {
- TRecord *r;
- M *first, *mp;
- int32 i;
-
- first = runtime_atomicloadp(&runtime_allm);
- n = 0;
- for(mp=first; mp; mp=mp->alllink)
- n++;
- ok = false;
- if(n <= p.__count) {
- ok = true;
- r = (TRecord*)p.__values;
- for(mp=first; mp; mp=mp->alllink) {
- for(i = 0; (uintptr)i < nelem(r->stk); i++) {
- r->stk[i] = mp->createstack[i].pc;
- }
- r++;
- }
- }
-}
-
-func Stack(b Slice, all bool) (n int) {
- byte *pc, *sp;
- bool enablegc;
-
- sp = runtime_getcallersp(&b);
- pc = runtime_getcallerpc(&b);
-
- if(all) {
- runtime_semacquire(&runtime_worldsema);
- runtime_m()->gcing = 1;
- runtime_stoptheworld();
- enablegc = mstats.enablegc;
- mstats.enablegc = false;
- }
-
- if(b.__count == 0)
- n = 0;
- else{
- G* g = runtime_g();
- g->writebuf = (byte*)b.__values;
- g->writenbuf = b.__count;
- USED(pc);
- USED(sp);
- runtime_goroutineheader(g);
- runtime_traceback();
- runtime_goroutinetrailer(g);
- if(all)
- runtime_tracebackothers(g);
- n = b.__count - g->writenbuf;
- g->writebuf = nil;
- g->writenbuf = 0;
- }
-
- if(all) {
- runtime_m()->gcing = 0;
- mstats.enablegc = enablegc;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- }
-}
-
-static void
-saveg(G *gp, TRecord *r)
-{
- int32 n, i;
- Location locstk[nelem(r->stk)];
-
- if(gp == runtime_g()) {
- n = runtime_callers(0, locstk, nelem(r->stk));
- for(i = 0; i < n; i++)
- r->stk[i] = locstk[i].pc;
- }
- else {
- // FIXME: Not implemented.
- n = 0;
- }
- if((size_t)n < nelem(r->stk))
- r->stk[n] = 0;
-}
-
-func GoroutineProfile(b Slice) (n int, ok bool) {
- TRecord *r;
- G *gp;
-
- ok = false;
- n = runtime_gcount();
- if(n <= b.__count) {
- runtime_semacquire(&runtime_worldsema);
- runtime_m()->gcing = 1;
- runtime_stoptheworld();
-
- n = runtime_gcount();
- if(n <= b.__count) {
- G* g = runtime_g();
- ok = true;
- r = (TRecord*)b.__values;
- saveg(g, r++);
- for(gp = runtime_allg; gp != nil; gp = gp->alllink) {
- if(gp == g || gp->status == Gdead)
- continue;
- saveg(gp, r++);
- }
- }
-
- runtime_m()->gcing = 0;
- runtime_semrelease(&runtime_worldsema);
- runtime_starttheworld();
- }
-}
-