123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * Performance counters
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "amd64.h"
- #include "pmc.h"
- enum{
- Qdir = 0,
- Qgctl,
- Qcore,
- Qctr,
- Qdata,
- Qctl,
- PmcCtlRdStr = 4*1024,
- };
- #define PMCTYPE(x) (((uintptr_t)x)&0xffful)
- #define PMCID(x) (((uintptr_t)x)>>12)
- #define PMCQID(i, t) ((((uintptr_t)i)<<12)|(t))
- Dirtab *pmctab;
- static int npmctab;
- Dirtab *toptab;
- static int ntoptab;
- int pmcdebug;
- static void
- topdirinit(int ncores)
- {
- int i;
- Dirtab *d;
- ntoptab = 2 + ncores;
- toptab = malloc(ntoptab * sizeof(Dirtab));
- if (toptab == nil)
- return;
- d = toptab;
- strncpy(d->name, ".", KNAMELEN);
- mkqid(&d->qid, Qdir, 0, QTDIR);
- d->perm = DMDIR|0555;
- d++;
- strncpy(d->name, "ctrdesc", KNAMELEN);
- mkqid(&d->qid, Qgctl, 0, 0);
- d->perm = 0444;
- for (i = 2; i < ncores + 2; i++) {
- d = &toptab[i];
- snprint(d->name, KNAMELEN, "core%4.4ud", i - 2);
- mkqid(&d->qid, PMCQID(i - 2, Qcore), 0, QTDIR);
- d->perm = DMDIR|0555;
- }
- }
- static void
- ctrdirinit(void)
- {
- int nr, i;
- Dirtab *d;
- nr = pmcnregs();
- npmctab = 1 + 2*nr;
- pmctab = malloc(npmctab * sizeof(Dirtab));
- if (pmctab == nil){
- free(toptab);
- toptab = nil;
- return;
- }
- d = pmctab;
- strncpy(d->name, ".", KNAMELEN);
- mkqid(&d->qid, Qctr, 0, QTDIR);
- d->perm = DMDIR|0555;
- for (i = 1; i < nr + 1; i++) {
- d = &pmctab[i];
- snprint(d->name, KNAMELEN, "ctr%2.2ud", i - 1);
- mkqid(&d->qid, PMCQID(i - 1, Qdata), 0, 0);
- d->perm = 0600;
- d = &pmctab[nr + i];
- snprint(d->name, KNAMELEN, "ctr%2.2udctl", i - 1);
- mkqid(&d->qid, PMCQID(i - 1, Qctl), 0, 0);
- d->perm = 0600;
- }
- }
- static void
- pmcnull(PmcCtl *p)
- {
- memset(p, 0xff, sizeof(PmcCtl));
- p->enab = PmcCtlNullval;
- p->user = PmcCtlNullval;
- p->os = PmcCtlNullval;
- p->reset = PmcCtlNullval;
- p->nodesc = 1;
- }
- static void
- pmcinit(void)
- {
- int i, j, ncores, nr;
- Mach *mp;
- _pmcupdate = pmcupdate;
- ncores = 0;
- nr = pmcnregs();
- for(i = 0; i < MACHMAX; i++)
- if((mp = sys->machptr[i]) != nil && mp->online){
- ncores++;
- for(j = 0; j < nr; j++)
- pmcnull(&mp->pmc[j]);
- }
- topdirinit(ncores);
- ctrdirinit();
- }
- static Chan *
- pmcattach(char *spec)
- {
- if (pmctab == nil)
- error(Enomem);
- return devattach(L'ε', spec);
- }
- int
- pmcgen(Chan *c, char *name, Dirtab* dir, int j, int s, Dir *dp)
- {
- int t, i, n;
- Dirtab *l, *d;
- if(s == DEVDOTDOT){
- devdir(c, (Qid){Qdir, 0, QTDIR}, "#ε", 0, eve, 0555, dp);
- c->aux = nil;
- return 1;
- }
- /* first, for directories, generate children */
- switch((int)PMCTYPE(c->qid.path)){
- case Qdir:
- return devgen(c, name, toptab, ntoptab, s, dp);
- case Qctr:
- return devgen(c, name, pmctab, npmctab, s, dp);
- case Qcore:
- c->aux = (void *)PMCID(c->qid.path); /* core no */
- return devgen(c, name, pmctab, npmctab, s, dp);
- default:
- if(s != 0)
- return -1;
- t = PMCTYPE(c->qid.path);
- if(t < Qctr){
- i = t;
- l = toptab;
- n = ntoptab;
- }else{
- i = PMCID(t);
- if (t == Qctl)
- i += (npmctab - 1)/2;
- l = pmctab;
- n = npmctab;
- }
- if(i >=n)
- return -1;
- d = &l[i];
- devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
- return 1;
- }
- }
- static Walkqid*
- pmcwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, nil, 0, pmcgen);
- }
- static int32_t
- pmcstat(Chan *c, uint8_t *dp, int32_t n)
- {
- return devstat(c, dp, n, nil, 0, pmcgen);
- }
- static Chan*
- pmcopen(Chan *c, int omode)
- {
- if (!iseve())
- error(Eperm);
- return devopen(c, omode, nil, 0, pmcgen);
- }
- static void
- pmcclose(Chan *c)
- {
- }
- static int32_t
- pmcread(Chan *c, void *a, int32_t n, int64_t offset)
- {
- Proc *up = externup();
- uint32_t type, id;
- PmcCtl p;
- char *s;
- uint64_t v;
- uint64_t coreno;
- type = PMCTYPE(c->qid.path);
- id = PMCID(c->qid.path);
- switch(type){
- case Qcore:
- case Qdir:
- case Qctr:
- return devdirread(c, a, n, nil, 0, pmcgen);
- }
- s = malloc(PmcCtlRdStr);
- if(waserror()){
- free(s);
- nexterror();
- }
- coreno = (uint64_t)c->aux;
- p._coreno = coreno;
- switch(type){
- case Qdata:
- v = pmcgetctr(coreno, id);
- snprint(s, PmcCtlRdStr, "%#ullx", v);
- break;
- case Qctl:
- if (pmcgetctl(coreno, &p, id) < 0)
- error("bad ctr");
- if (pmcctlstr(s, PmcCtlRdStr, &p) < 0)
- error("bad pmc");
- break;
- case Qgctl:
- if (pmcdescstr(s, PmcCtlRdStr) < 0)
- error("bad pmc");
- break;
- default:
- error(Eperm);
- }
- n = readstr(offset, a, n, s);
- free(s);
- poperror();
- return n;
- }
- enum{
- Enable,
- Disable,
- User,
- Os,
- NoUser,
- NoOs,
- Reset,
- Debug,
- };
- static Cmdtab pmcctlmsg[] =
- {
- Enable, "enable", 0,
- Disable, "disable", 0,
- User, "user", 0,
- Os, "os", 0,
- NoUser, "nouser", 0,
- NoOs, "noos", 0,
- Reset, "reset", 0,
- Debug, "debug", 0,
- };
- typedef void (*APfunc)(void);
- typedef struct AcPmcArg AcPmcArg;
- struct AcPmcArg {
- int regno;
- int coreno;
- PmcCtl;
- };
- typedef struct AcCtrArg AcCtrArg;
- struct AcCtrArg {
- int regno;
- int coreno;
- uint64_t v;
- };
- void
- acpmcsetctl(void)
- {
- Proc *up = externup();
- AcPmcArg p;
- Mach *mp;
- mp = up->ac;
- memmove(&p, mp->icc->data, sizeof(AcPmcArg));
- mp->icc->rc = pmcsetctl(p.coreno, &p, p.regno);
- return;
- }
- void
- acpmcsetctr(void)
- {
- Proc *up = externup();
- AcCtrArg ctr;
- Mach *mp;
- mp = up->ac;
- memmove(&ctr, mp->icc->data, sizeof(AcCtrArg));
- mp->icc->rc = pmcsetctr(ctr.coreno, ctr.v, ctr.regno);
- return;
- }
- static int32_t
- pmcwrite(Chan *c, void *a, int32_t n, int64_t mm)
- {
- Proc *up = externup();
- Cmdbuf *cb;
- Cmdtab *ct;
- uint32_t type;
- char str[64]; /* 0x0000000000000000\0 */
- AcPmcArg p;
- AcCtrArg ctr;
- uint64_t coreno;
- Mach *mp;
- if (c->qid.type == QTDIR)
- error(Eperm);
- if (c->qid.path == Qgctl)
- error(Eperm);
- if (n >= sizeof(str))
- error(Ebadctl);
- pmcnull(&p);
- coreno = (uint64_t)c->aux;
- p.coreno = coreno;
- type = PMCTYPE(c->qid.path);
- p.regno = PMCID(c->qid.path);
- memmove(str, a, n);
- str[n] = '\0';
- mp = up->ac;
- ctr.coreno = coreno;
- ctr.regno = p.regno;
- if (type == Qdata) {
- /* I am a handler for a proc in the core, run an RPC*/
- if (mp != nil && mp->machno == coreno) {
- if (runac(mp, acpmcsetctr, 0, &ctr, sizeof(AcCtrArg)) < 0)
- n = -1;
- } else {
- if (pmcsetctr(coreno, strtoull(str, 0, 0), p.regno) < 0)
- n = -1;
- }
- return n;
- }
- /* TODO: should iterate through multiple lines */
- if (strncmp(str, "set ", 4) == 0){
- memmove(p.descstr, (char *)str + 4, n - 4);
- p.descstr[n - 4] = '\0';
- p.nodesc = 0;
- } else {
- cb = parsecmd(a, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, pmcctlmsg, nelem(pmcctlmsg));
- switch(ct->index){
- case Enable:
- p.enab = 1;
- break;
- case Disable:
- p.enab = 0;
- break;
- case User:
- p.user = 1;
- break;
- case Os:
- p.os = 1;
- break;
- case NoUser:
- p.user = 0;
- break;
- case NoOs:
- p.os = 0;
- break;
- case Reset:
- p.reset = 1;
- break;
- case Debug:
- pmcdebug = ~pmcdebug;
- break;
- default:
- cmderror(cb, "invalid ctl");
- break;
- }
- free(cb);
- poperror();
- }
- /* I am a handler for a proc in the core, run an RPC*/
- if (mp != nil && mp->machno == coreno) {
- if (runac(mp, acpmcsetctl, 0, &p, sizeof(AcPmcArg)) < 0)
- n = -1;
- } else {
- if (pmcsetctl(coreno, &p, p.regno) < 0)
- n = -1;
- }
- return n;
- }
- Dev pmcdevtab = {
- L'ε',
- "pmc",
- pmcinit,
- devinit,
- devshutdown,
- pmcattach,
- pmcwalk,
- pmcstat,
- pmcopen,
- devcreate,
- pmcclose,
- pmcread,
- devbread,
- pmcwrite,
- devbwrite,
- devremove,
- devwstat,
- };
|