123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- #include "dat.h"
- #include "fns.h"
- #include "error.h"
- #include "interp.h"
- enum
- {
- Qdir,
- Qctl,
- Qstate,
- Qsum,
- Qevent,
- Qprof,
- Qheap,
- Qgc
- };
- static
- Dirtab memdir[] =
- {
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "memctl", {Qctl}, 0, 0666,
- "memstate", {Qstate}, 0, 0444,
- "memsum", {Qsum}, 0, 0444,
- "memevent", {Qevent}, 0, 0444,
- "memprof", {Qprof}, 0, 0444,
- "memheap", {Qheap}, 0, 0444,
- "memgc", {Qgc}, 0, 0444,
- };
- enum
- {
- /* these are the top two bits of size */
- Pflags= 3<<30,
- Pfree= 0<<30,
- Palloc= 1<<30,
- Paend= 2<<30,
- Pimmutable= 3<<30,
- Npool = 3,
- Nevent = 10000,
- Nstate = 12000
- };
- /*
- * pool snapshots
- */
- typedef struct Pstate Pstate;
- struct Pstate
- {
- ulong base;
- ulong size;
- };
- static struct
- {
- Pstate state[3+Nstate];
- Pstate* lim;
- Pstate* ptr;
- int summary;
- } poolstate[Npool];
- static Ref stateopen;
- /*
- * pool/heap allocation events
- */
- typedef struct Pevent Pevent;
- struct Pevent
- {
- int pool;
- ulong pc;
- ulong base;
- ulong size;
- };
- static struct
- {
- Lock l;
- Ref inuse;
- Rendez r;
- int open;
- Pevent events[Nevent];
- int rd;
- int wr;
- int full;
- int want;
- ulong lost;
- } poolevents;
- /*
- * allocation profiles
- */
- typedef struct Pprof Pprof;
- typedef struct Pbucket Pbucket;
- struct Pbucket
- {
- ulong val;
- ulong pool;
- ulong count;
- ulong size;
- Pbucket* next;
- };
- static struct {
- Ref inuse; /* only one of these things */
- Lock l;
- Pbucket buckets[1000];
- Pbucket snap[1000];
- int used;
- int snapped;
- Pbucket* hash[128];
- ulong lost;
- } memprof;
- extern void (*memmonitor)(int, ulong, ulong, ulong);
- extern ulong gcnruns;
- extern ulong gcsweeps;
- extern ulong gcbroken;
- extern ulong gchalted;
- extern ulong gcepochs;
- extern uvlong gcdestroys;
- extern uvlong gcinspects;
- extern uvlong gcbusy;
- extern uvlong gcidle;
- extern uvlong gcidlepass;
- extern uvlong gcpartial;
- static void
- mprofreset(void)
- {
- lock(&memprof.l); /* need ilock in kernel */
- memset(memprof.hash, 0, sizeof(memprof.hash));
- memprof.used = 0;
- memprof.lost = 0;
- unlock(&memprof.l);
- }
- static void
- mprofmonitor(int pool, ulong pc, ulong base, ulong size)
- {
- Pbucket **h0, **h, *p;
- if((pool&7) == 1)
- return; /* ignore heap */
- USED(base);
- h0 = &memprof.hash[((pc>>16)^(pc>>4))&(nelem(memprof.hash)-1)];
- lock(&memprof.l);
- for(h = h0; (p = *h) != nil; h = &p->next)
- if(p->val == pc && p->pool == pool){
- p->count++;
- p->size += size;
- *h = p->next;
- p->next = *h0;
- *h0 = p;
- unlock(&memprof.l);
- return;
- }
- if(memprof.used >= nelem(memprof.buckets)){
- memprof.lost++;
- unlock(&memprof.l);
- return;
- }
- p = &memprof.buckets[memprof.used++];
- p->val = pc;
- p->pool = pool;
- p->count = 1;
- p->size = size;
- p->next = *h0;
- *h0 = p;
- unlock(&memprof.l);
- }
- static void
- _memmonitor(int pool, ulong pc, ulong base, ulong size)
- {
- Pevent e;
- e.pool = pool;
- e.pc = pc;
- e.base = base;
- e.size = size;
- lock(&poolevents.l);
- if(!poolevents.full){
- poolevents.events[poolevents.wr] = e;
- if(++poolevents.wr == nelem(poolevents.events))
- poolevents.wr = 0;
- if(poolevents.wr == poolevents.rd)
- poolevents.full = 1;
- }else
- poolevents.lost++;
- if(poolevents.want){
- poolevents.want = 0;
- Wakeup(&poolevents.r);
- }
- unlock(&poolevents.l);
- }
- static int
- ismemdata(void *v)
- {
- USED(v);
- return poolevents.full || poolevents.rd != poolevents.wr;
- }
- static char*
- memaudit(int pno, Bhdr *b)
- {
- Pstate *p;
- if(pno >= Npool)
- return "too many pools for memaudit";
- if((p = poolstate[pno].ptr) == poolstate[pno].lim){
- if(b->magic == MAGIC_E)
- return nil;
- p = &poolstate[pno].state[1];
- if(b->magic == MAGIC_F)
- p++;
- p->base++;
- p->size += b->size;
- return nil;
- }
- poolstate[pno].ptr++;
- p->base = (ulong)b;
- p->size = b->size;
- switch(b->magic){
- case MAGIC_A:
- p->size |= Palloc;
- break;
- case MAGIC_F:
- p->size |= Pfree;
- break;
- case MAGIC_E:
- p->size = b->csize | Paend;
- break;
- case MAGIC_I:
- p->size |= Pimmutable;
- break;
- default:
- return "bad magic number in block";
- }
- return nil;
- }
- static void
- mput4(uchar *m, ulong v)
- {
- m[0] = v>>24;
- m[1] = v>>16;
- m[2] = v>>8;
- m[3] = v;
- }
- static Chan*
- memattach(char *spec)
- {
- return devattach('%', spec);
- }
- static Walkqid*
- memwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, memdir, nelem(memdir), devgen);
- }
- static int
- memstat(Chan *c, uchar *db, int n)
- {
- return devstat(c, db, n, memdir, nelem(memdir), devgen);
- }
- static Chan*
- memopen(Chan *c, int omode)
- {
- if(memmonitor != nil && c->qid.path != Qgc)
- error(Einuse);
- c = devopen(c, omode, memdir, nelem(memdir), devgen);
- switch((ulong)c->qid.path){
- case Qevent:
- if(incref(&poolevents.inuse) != 1){
- decref(&poolevents.inuse);
- c->flag &= ~COPEN;
- error(Einuse);
- }
- poolevents.rd = poolevents.wr = 0;
- poolevents.full = 0;
- poolevents.want = 0;
- poolevents.lost = 0;
- memmonitor = _memmonitor;
- poolevents.open = 1;
- break;
- case Qstate:
- if(incref(&stateopen) != 1){
- decref(&stateopen);
- c->flag &= ~COPEN;
- error(Einuse);
- }
- break;
- case Qprof:
- if(incref(&memprof.inuse) != 1){
- decref(&memprof.inuse);
- c->flag &= ~COPEN;
- error(Einuse);
- }
- memmonitor = mprofmonitor;
- break;
- }
- return c;
- }
- static void
- memclose(Chan *c)
- {
- if((c->flag & COPEN) == 0)
- return;
- switch((ulong)c->qid.path) {
- case Qevent:
- memmonitor = nil;
- poolevents.open = 0;
- decref(&poolevents.inuse);
- break;
- case Qstate:
- decref(&stateopen);
- break;
- case Qprof:
- decref(&memprof.inuse);
- memmonitor = nil;
- break;
- }
- }
- static long
- memread(Chan *c, void *va, long count, vlong offset)
- {
- uchar *m;
- char *e, *s;
- int i, summary;
- long n, nr;
- Pstate *p;
- Pevent pe;
- Pbucket *b;
- if(c->qid.type & QTDIR)
- return devdirread(c, va, count, memdir, nelem(memdir), devgen);
- summary = 0;
- switch((ulong)c->qid.path) {
- default:
- error(Egreg);
- case Qctl:
- return 0;
- case Qsum:
- summary = 1;
- /* fall through */
- case Qstate:
- if(offset == 0){
- for(i=0; i<Npool; i++){
- poolstate[i].ptr = &poolstate[i].state[3];
- poolstate[i].lim = poolstate[i].ptr + Nstate;
- memset(poolstate[i].state, 0, sizeof(poolstate[i].state));
- poolstate[i].summary = summary;
- }
- e = poolaudit(memaudit);
- if(e != nil){
- print("mem: %s\n", e);
- error(e);
- }
- }
- m = va;
- nr = offset/8;
- for(i=0; i<Npool && count >= 8; i++){
- n = poolstate[i].ptr - poolstate[i].state;
- poolstate[i].state[0].base = i;
- poolstate[i].state[0].size = n;
- if(nr >= n){
- nr -= n;
- continue;
- }
- n -= nr;
- p = &poolstate[i].state[nr];
- for(; --n >= 0 && (count -= 8) >= 0; m += 8, p++){
- mput4(m, p->base);
- mput4(m+4, p->size);
- }
- }
- return m-(uchar*)va;
- case Qevent:
- while(!ismemdata(nil)){
- poolevents.want = 1;
- Sleep(&poolevents.r, ismemdata, nil);
- }
- m = va;
- do{
- if((count -= 4*4) < 0)
- return m-(uchar*)va;
- pe = poolevents.events[poolevents.rd];
- mput4(m, pe.pool);
- mput4(m+4, pe.pc);
- mput4(m+8, pe.base);
- mput4(m+12, pe.size);
- m += 4*4;
- if(++poolevents.rd >= nelem(poolevents.events))
- poolevents.rd = 0;
- }while(poolevents.rd != poolevents.wr);
- poolevents.full = 0;
- return m-(uchar*)va;
- case Qprof:
- if(offset == 0){
- lock(&memprof.l);
- memmove(memprof.snap, memprof.buckets, memprof.used*sizeof(memprof.buckets[0]));
- memprof.snapped = memprof.used;
- unlock(&memprof.l);
- }
- m = va;
- for(i = offset/(4*4); i < memprof.snapped && (count -= 4*4) >= 0; i++){
- b = &memprof.snap[i];
- mput4(m, b->pool);
- mput4(m+4, b->val);
- mput4(m+8, b->count);
- mput4(m+12, b->size);
- m += 4*4;
- }
- return m-(uchar*)va;
- case Qgc:
- s = malloc(READSTR);
- if(s == nil)
- error(Enomem);
- if(waserror()){
- free(s);
- nexterror();
- }
- snprint(s, READSTR, "runs: %lud\nsweeps: %lud\nbchain: %lud\nhalted: %lud\nepochs: %lud\ndestroy: %llud\ninspects: %llud\nbusy: %llud\nidle: %llud\nidlepass: %llud\npartial: %llud\n",
- gcnruns, gcsweeps, gcbroken, gchalted, gcepochs, gcdestroys, gcinspects, gcbusy, gcidle, gcidlepass, gcpartial);
- count = readstr(offset, va, count, s);
- poperror();
- free(s);
- return count;
- }
- }
- static long
- memwrite(Chan *c, void *va, long count, vlong offset)
- {
- USED(offset);
- USED(count);
- USED(va);
- if(c->qid.type & QTDIR)
- error(Eperm);
- switch((ulong)c->qid.path) {
- default:
- error(Egreg);
- case Qctl:
- error(Ebadarg);
- case Qstate:
- error(Eperm);
- case Qprof:
- mprofreset();
- break;
- }
- return 0;
- }
- Dev memdevtab = {
- '%',
- "mem",
- devinit,
- memattach,
- memwalk,
- memstat,
- memopen,
- devcreate,
- memclose,
- memread,
- devbread,
- memwrite,
- devbwrite,
- devremove,
- devwstat
- };
|