devpmc.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * Performance counters
  11. */
  12. #include "u.h"
  13. #include "../port/lib.h"
  14. #include "mem.h"
  15. #include "dat.h"
  16. #include "fns.h"
  17. #include "../port/error.h"
  18. #include "amd64.h"
  19. #include "pmc.h"
  20. enum{
  21. Qdir = 0,
  22. Qgctl,
  23. Qcore,
  24. Qctr,
  25. Qdata,
  26. Qctl,
  27. PmcCtlRdStr = 4*1024,
  28. };
  29. #define PMCTYPE(x) (((uintptr_t)x)&0xffful)
  30. #define PMCID(x) (((uintptr_t)x)>>12)
  31. #define PMCQID(i, t) ((((uintptr_t)i)<<12)|(t))
  32. Dirtab *pmctab;
  33. static int npmctab;
  34. Dirtab *toptab;
  35. static int ntoptab;
  36. int pmcdebug;
  37. static void
  38. topdirinit(int ncores)
  39. {
  40. int i;
  41. Dirtab *d;
  42. ntoptab = 2 + ncores;
  43. toptab = malloc(ntoptab * sizeof(Dirtab));
  44. if (toptab == nil)
  45. return;
  46. d = toptab;
  47. strncpy(d->name, ".", KNAMELEN);
  48. mkqid(&d->qid, Qdir, 0, QTDIR);
  49. d->perm = DMDIR|0555;
  50. d++;
  51. strncpy(d->name, "ctrdesc", KNAMELEN);
  52. mkqid(&d->qid, Qgctl, 0, 0);
  53. d->perm = 0444;
  54. for (i = 2; i < ncores + 2; i++) {
  55. d = &toptab[i];
  56. snprint(d->name, KNAMELEN, "core%4.4ud", i - 2);
  57. mkqid(&d->qid, PMCQID(i - 2, Qcore), 0, QTDIR);
  58. d->perm = DMDIR|0555;
  59. }
  60. }
  61. static void
  62. ctrdirinit(void)
  63. {
  64. int nr, i;
  65. Dirtab *d;
  66. nr = pmcnregs();
  67. npmctab = 1 + 2*nr;
  68. pmctab = malloc(npmctab * sizeof(Dirtab));
  69. if (pmctab == nil){
  70. free(toptab);
  71. toptab = nil;
  72. return;
  73. }
  74. d = pmctab;
  75. strncpy(d->name, ".", KNAMELEN);
  76. mkqid(&d->qid, Qctr, 0, QTDIR);
  77. d->perm = DMDIR|0555;
  78. for (i = 1; i < nr + 1; i++) {
  79. d = &pmctab[i];
  80. snprint(d->name, KNAMELEN, "ctr%2.2ud", i - 1);
  81. mkqid(&d->qid, PMCQID(i - 1, Qdata), 0, 0);
  82. d->perm = 0600;
  83. d = &pmctab[nr + i];
  84. snprint(d->name, KNAMELEN, "ctr%2.2udctl", i - 1);
  85. mkqid(&d->qid, PMCQID(i - 1, Qctl), 0, 0);
  86. d->perm = 0600;
  87. }
  88. }
  89. static void
  90. pmcnull(PmcCtl *p)
  91. {
  92. memset(p, 0xff, sizeof(PmcCtl));
  93. p->enab = PmcCtlNullval;
  94. p->user = PmcCtlNullval;
  95. p->os = PmcCtlNullval;
  96. p->reset = PmcCtlNullval;
  97. p->nodesc = 1;
  98. }
  99. static void
  100. pmcinit(void)
  101. {
  102. int i, j, ncores, nr;
  103. Mach *mp;
  104. _pmcupdate = pmcupdate;
  105. ncores = 0;
  106. nr = pmcnregs();
  107. for(i = 0; i < MACHMAX; i++)
  108. if((mp = sys->machptr[i]) != nil && mp->online){
  109. ncores++;
  110. for(j = 0; j < nr; j++)
  111. pmcnull(&mp->pmc[j]);
  112. }
  113. topdirinit(ncores);
  114. ctrdirinit();
  115. }
  116. static Chan *
  117. pmcattach(char *spec)
  118. {
  119. if (pmctab == nil)
  120. error(Enomem);
  121. return devattach(L'ε', spec);
  122. }
  123. int
  124. pmcgen(Chan *c, char *name, Dirtab* dir, int j, int s, Dir *dp)
  125. {
  126. int t, i, n;
  127. Dirtab *l, *d;
  128. if(s == DEVDOTDOT){
  129. devdir(c, (Qid){Qdir, 0, QTDIR}, "#ε", 0, eve, 0555, dp);
  130. c->aux = nil;
  131. return 1;
  132. }
  133. /* first, for directories, generate children */
  134. switch((int)PMCTYPE(c->qid.path)){
  135. case Qdir:
  136. return devgen(c, name, toptab, ntoptab, s, dp);
  137. case Qctr:
  138. return devgen(c, name, pmctab, npmctab, s, dp);
  139. case Qcore:
  140. c->aux = (void *)PMCID(c->qid.path); /* core no */
  141. return devgen(c, name, pmctab, npmctab, s, dp);
  142. default:
  143. if(s != 0)
  144. return -1;
  145. t = PMCTYPE(c->qid.path);
  146. if(t < Qctr){
  147. i = t;
  148. l = toptab;
  149. n = ntoptab;
  150. }else{
  151. i = PMCID(t);
  152. if (t == Qctl)
  153. i += (npmctab - 1)/2;
  154. l = pmctab;
  155. n = npmctab;
  156. }
  157. if(i >=n)
  158. return -1;
  159. d = &l[i];
  160. devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
  161. return 1;
  162. }
  163. }
  164. static Walkqid*
  165. pmcwalk(Chan *c, Chan *nc, char **name, int nname)
  166. {
  167. return devwalk(c, nc, name, nname, nil, 0, pmcgen);
  168. }
  169. static int32_t
  170. pmcstat(Chan *c, uint8_t *dp, int32_t n)
  171. {
  172. return devstat(c, dp, n, nil, 0, pmcgen);
  173. }
  174. static Chan*
  175. pmcopen(Chan *c, int omode)
  176. {
  177. if (!iseve())
  178. error(Eperm);
  179. return devopen(c, omode, nil, 0, pmcgen);
  180. }
  181. static void
  182. pmcclose(Chan *c)
  183. {
  184. }
  185. static int32_t
  186. pmcread(Chan *c, void *a, int32_t n, int64_t offset)
  187. {
  188. Proc *up = externup();
  189. uint32_t type, id;
  190. PmcCtl p;
  191. char *s;
  192. uint64_t v;
  193. uint64_t coreno;
  194. type = PMCTYPE(c->qid.path);
  195. id = PMCID(c->qid.path);
  196. switch(type){
  197. case Qcore:
  198. case Qdir:
  199. case Qctr:
  200. return devdirread(c, a, n, nil, 0, pmcgen);
  201. }
  202. s = malloc(PmcCtlRdStr);
  203. if(waserror()){
  204. free(s);
  205. nexterror();
  206. }
  207. coreno = (uint64_t)c->aux;
  208. p._coreno = coreno;
  209. switch(type){
  210. case Qdata:
  211. v = pmcgetctr(coreno, id);
  212. snprint(s, PmcCtlRdStr, "%#ullx", v);
  213. break;
  214. case Qctl:
  215. if (pmcgetctl(coreno, &p, id) < 0)
  216. error("bad ctr");
  217. if (pmcctlstr(s, PmcCtlRdStr, &p) < 0)
  218. error("bad pmc");
  219. break;
  220. case Qgctl:
  221. if (pmcdescstr(s, PmcCtlRdStr) < 0)
  222. error("bad pmc");
  223. break;
  224. default:
  225. error(Eperm);
  226. }
  227. n = readstr(offset, a, n, s);
  228. free(s);
  229. poperror();
  230. return n;
  231. }
  232. enum{
  233. Enable,
  234. Disable,
  235. User,
  236. Os,
  237. NoUser,
  238. NoOs,
  239. Reset,
  240. Debug,
  241. };
  242. static Cmdtab pmcctlmsg[] =
  243. {
  244. Enable, "enable", 0,
  245. Disable, "disable", 0,
  246. User, "user", 0,
  247. Os, "os", 0,
  248. NoUser, "nouser", 0,
  249. NoOs, "noos", 0,
  250. Reset, "reset", 0,
  251. Debug, "debug", 0,
  252. };
  253. typedef void (*APfunc)(void);
  254. typedef struct AcPmcArg AcPmcArg;
  255. struct AcPmcArg {
  256. int regno;
  257. int coreno;
  258. PmcCtl;
  259. };
  260. typedef struct AcCtrArg AcCtrArg;
  261. struct AcCtrArg {
  262. int regno;
  263. int coreno;
  264. uint64_t v;
  265. };
  266. void
  267. acpmcsetctl(void)
  268. {
  269. Proc *up = externup();
  270. AcPmcArg p;
  271. Mach *mp;
  272. mp = up->ac;
  273. memmove(&p, mp->icc->data, sizeof(AcPmcArg));
  274. mp->icc->rc = pmcsetctl(p.coreno, &p, p.regno);
  275. return;
  276. }
  277. void
  278. acpmcsetctr(void)
  279. {
  280. Proc *up = externup();
  281. AcCtrArg ctr;
  282. Mach *mp;
  283. mp = up->ac;
  284. memmove(&ctr, mp->icc->data, sizeof(AcCtrArg));
  285. mp->icc->rc = pmcsetctr(ctr.coreno, ctr.v, ctr.regno);
  286. return;
  287. }
  288. static int32_t
  289. pmcwrite(Chan *c, void *a, int32_t n, int64_t mm)
  290. {
  291. Proc *up = externup();
  292. Cmdbuf *cb;
  293. Cmdtab *ct;
  294. uint32_t type;
  295. char str[64]; /* 0x0000000000000000\0 */
  296. AcPmcArg p;
  297. AcCtrArg ctr;
  298. uint64_t coreno;
  299. Mach *mp;
  300. if (c->qid.type == QTDIR)
  301. error(Eperm);
  302. if (c->qid.path == Qgctl)
  303. error(Eperm);
  304. if (n >= sizeof(str))
  305. error(Ebadctl);
  306. pmcnull(&p);
  307. coreno = (uint64_t)c->aux;
  308. p.coreno = coreno;
  309. type = PMCTYPE(c->qid.path);
  310. p.regno = PMCID(c->qid.path);
  311. memmove(str, a, n);
  312. str[n] = '\0';
  313. mp = up->ac;
  314. ctr.coreno = coreno;
  315. ctr.regno = p.regno;
  316. if (type == Qdata) {
  317. /* I am a handler for a proc in the core, run an RPC*/
  318. if (mp != nil && mp->machno == coreno) {
  319. if (runac(mp, acpmcsetctr, 0, &ctr, sizeof(AcCtrArg)) < 0)
  320. n = -1;
  321. } else {
  322. if (pmcsetctr(coreno, strtoull(str, 0, 0), p.regno) < 0)
  323. n = -1;
  324. }
  325. return n;
  326. }
  327. /* TODO: should iterate through multiple lines */
  328. if (strncmp(str, "set ", 4) == 0){
  329. memmove(p.descstr, (char *)str + 4, n - 4);
  330. p.descstr[n - 4] = '\0';
  331. p.nodesc = 0;
  332. } else {
  333. cb = parsecmd(a, n);
  334. if(waserror()){
  335. free(cb);
  336. nexterror();
  337. }
  338. ct = lookupcmd(cb, pmcctlmsg, nelem(pmcctlmsg));
  339. switch(ct->index){
  340. case Enable:
  341. p.enab = 1;
  342. break;
  343. case Disable:
  344. p.enab = 0;
  345. break;
  346. case User:
  347. p.user = 1;
  348. break;
  349. case Os:
  350. p.os = 1;
  351. break;
  352. case NoUser:
  353. p.user = 0;
  354. break;
  355. case NoOs:
  356. p.os = 0;
  357. break;
  358. case Reset:
  359. p.reset = 1;
  360. break;
  361. case Debug:
  362. pmcdebug = ~pmcdebug;
  363. break;
  364. default:
  365. cmderror(cb, "invalid ctl");
  366. break;
  367. }
  368. free(cb);
  369. poperror();
  370. }
  371. /* I am a handler for a proc in the core, run an RPC*/
  372. if (mp != nil && mp->machno == coreno) {
  373. if (runac(mp, acpmcsetctl, 0, &p, sizeof(AcPmcArg)) < 0)
  374. n = -1;
  375. } else {
  376. if (pmcsetctl(coreno, &p, p.regno) < 0)
  377. n = -1;
  378. }
  379. return n;
  380. }
  381. Dev pmcdevtab = {
  382. L'ε',
  383. "pmc",
  384. pmcinit,
  385. devinit,
  386. devshutdown,
  387. pmcattach,
  388. pmcwalk,
  389. pmcstat,
  390. pmcopen,
  391. devcreate,
  392. pmcclose,
  393. pmcread,
  394. devbread,
  395. pmcwrite,
  396. devbwrite,
  397. devremove,
  398. devwstat,
  399. };