#include "runtime.h"
#include "arch.h"
#include "malloc.h"
#include "defs.h"
#include "type.h"

#line 16 "/go/src/pkg/runtime/mprof.goc"
static Lock proflock; 
#line 20 "/go/src/pkg/runtime/mprof.goc"
typedef struct Bucket Bucket; 
struct Bucket 
{ 
Bucket *next; 
Bucket *allnext; 
uintptr allocs; 
uintptr frees; 
uintptr alloc_bytes; 
uintptr free_bytes; 
uintptr hash; 
uintptr nstk; 
uintptr stk[1]; 
} ; 
enum { 
BuckHashSize = 179999 , 
} ; 
static Bucket **buckhash; 
static Bucket *buckets; 
static uintptr bucketmem; 
#line 41 "/go/src/pkg/runtime/mprof.goc"
static Bucket* 
stkbucket ( uintptr *stk , int32 nstk ) 
{ 
int32 i; 
uintptr h; 
Bucket *b; 
#line 48 "/go/src/pkg/runtime/mprof.goc"
if ( buckhash == nil ) { 
buckhash = runtime·SysAlloc ( BuckHashSize*sizeof buckhash[0] ) ; 
mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0]; 
} 
#line 54 "/go/src/pkg/runtime/mprof.goc"
h = 0; 
for ( i=0; i<nstk; i++ ) { 
h += stk[i]; 
h += h<<10; 
h ^= h>>6; 
} 
h += h<<3; 
h ^= h>>11; 
#line 63 "/go/src/pkg/runtime/mprof.goc"
i = h%BuckHashSize; 
for ( b = buckhash[i]; b; b=b->next ) 
if ( b->hash == h && b->nstk == nstk && 
runtime·mcmp ( ( byte* ) b->stk , ( byte* ) stk , nstk*sizeof stk[0] ) == 0 ) 
return b; 
#line 69 "/go/src/pkg/runtime/mprof.goc"
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->hash = h; 
b->nstk = nstk; 
b->next = buckhash[i]; 
buckhash[i] = b; 
b->allnext = buckets; 
buckets = b; 
return b; 
} 
#line 89 "/go/src/pkg/runtime/mprof.goc"
typedef struct AddrHash AddrHash; 
typedef struct AddrEntry AddrEntry; 
#line 92 "/go/src/pkg/runtime/mprof.goc"
struct AddrHash 
{ 
AddrHash *next; 
uintptr addr; 
AddrEntry *dense[1<<13]; 
} ; 
#line 99 "/go/src/pkg/runtime/mprof.goc"
struct AddrEntry 
{ 
AddrEntry *next; 
uint32 addr; 
Bucket *b; 
} ; 
#line 106 "/go/src/pkg/runtime/mprof.goc"
enum { 
AddrHashBits = 12 
} ; 
static AddrHash *addrhash[1<<AddrHashBits]; 
static AddrEntry *addrfree; 
static uintptr addrmem; 
#line 118 "/go/src/pkg/runtime/mprof.goc"
enum { 
HashMultiplier = 2654435769U 
} ; 
#line 123 "/go/src/pkg/runtime/mprof.goc"
static void 
setaddrbucket ( uintptr addr , Bucket *b ) 
{ 
int32 i; 
uint32 h; 
AddrHash *ah; 
AddrEntry *e; 
#line 131 "/go/src/pkg/runtime/mprof.goc"
h = ( uint32 ) ( ( addr>>20 ) *HashMultiplier ) >> ( 32-AddrHashBits ) ; 
for ( ah=addrhash[h]; ah; ah=ah->next ) 
if ( ah->addr == ( addr>>20 ) ) 
goto found; 
#line 136 "/go/src/pkg/runtime/mprof.goc"
ah = runtime·mallocgc ( sizeof *ah , FlagNoProfiling , 0 , 1 ) ; 
addrmem += sizeof *ah; 
ah->next = addrhash[h]; 
ah->addr = addr>>20; 
addrhash[h] = ah; 
#line 142 "/go/src/pkg/runtime/mprof.goc"
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<<20 ) -1 ) ) ; 
e->b = b; 
h = ( addr>>7 ) & ( nelem ( ah->dense ) -1 ) ; 
e->next = ah->dense[h]; 
ah->dense[h] = e; 
} 
#line 159 "/go/src/pkg/runtime/mprof.goc"
static Bucket* 
getaddrbucket ( uintptr addr ) 
{ 
uint32 h; 
AddrHash *ah; 
AddrEntry *e , **l; 
Bucket *b; 
#line 167 "/go/src/pkg/runtime/mprof.goc"
h = ( uint32 ) ( ( addr>>20 ) *HashMultiplier ) >> ( 32-AddrHashBits ) ; 
for ( ah=addrhash[h]; ah; ah=ah->next ) 
if ( ah->addr == ( addr>>20 ) ) 
goto found; 
return nil; 
#line 173 "/go/src/pkg/runtime/mprof.goc"
found: 
h = ( addr>>7 ) & ( nelem ( ah->dense ) -1 ) ; 
for ( l=&ah->dense[h]; ( e=*l ) != nil; l=&e->next ) { 
if ( e->addr == ( uint32 ) ~ ( addr & ( ( 1<<20 ) -1 ) ) ) { 
*l = e->next; 
b = e->b; 
e->next = addrfree; 
addrfree = e; 
return b; 
} 
} 
return nil; 
} 
#line 188 "/go/src/pkg/runtime/mprof.goc"
void 
runtime·MProf_Malloc ( void *p , uintptr size ) 
{ 
int32 nstk; 
uintptr stk[32]; 
Bucket *b; 
#line 195 "/go/src/pkg/runtime/mprof.goc"
if ( m->nomemprof > 0 ) 
return; 
#line 198 "/go/src/pkg/runtime/mprof.goc"
m->nomemprof++; 
nstk = runtime·callers ( 1 , stk , 32 ) ; 
runtime·lock ( &proflock ) ; 
b = stkbucket ( stk , nstk ) ; 
b->allocs++; 
b->alloc_bytes += size; 
setaddrbucket ( ( uintptr ) p , b ) ; 
runtime·unlock ( &proflock ) ; 
m->nomemprof--; 
} 
#line 210 "/go/src/pkg/runtime/mprof.goc"
void 
runtime·MProf_Free ( void *p , uintptr size ) 
{ 
Bucket *b; 
#line 215 "/go/src/pkg/runtime/mprof.goc"
if ( m->nomemprof > 0 ) 
return; 
#line 218 "/go/src/pkg/runtime/mprof.goc"
m->nomemprof++; 
runtime·lock ( &proflock ) ; 
b = getaddrbucket ( ( uintptr ) p ) ; 
if ( b != nil ) { 
b->frees++; 
b->free_bytes += size; 
} 
runtime·unlock ( &proflock ) ; 
m->nomemprof--; 
} 
#line 234 "/go/src/pkg/runtime/mprof.goc"
typedef struct Record Record; 
struct Record { 
int64 alloc_bytes , free_bytes; 
int64 alloc_objects , free_objects; 
uintptr stk[32]; 
} ; 
#line 242 "/go/src/pkg/runtime/mprof.goc"
static void 
record ( Record *r , Bucket *b ) 
{ 
int32 i; 
#line 247 "/go/src/pkg/runtime/mprof.goc"
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]; 
for ( ; i<nelem ( r->stk ) ; i++ ) 
r->stk[i] = 0; 
} 
void
runtime·MemProfile(Slice p, bool include_inuse_zero, uint8, uint16, int32 n, bool ok)
{
#line 257 "/go/src/pkg/runtime/mprof.goc"

	Bucket *b;
	Record *r;

	runtime·lock(&proflock);
	n = 0;
	for(b=buckets; b; b=b->allnext)
		if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
			n++;
	ok = false;
	if(n <= p.len) {
		ok = true;
		r = (Record*)p.array;
		for(b=buckets; b; b=b->allnext)
			if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
				record(r++, b);
	}
	runtime·unlock(&proflock);
	FLUSH(&n);
	FLUSH(&ok);
}
