devpmc.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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) (((unsigned)x)&0xffful)
  30. #define PMCID(x) (((unsigned)x)>>12)
  31. #define PMCQID(i, t) ((((unsigned)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*, int, 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 *)
  183. {
  184. }
  185. static int32_t
  186. pmcread(Chan *c, void *a, int32_t n, int64_t offset)
  187. {
  188. uint32_t type, id;
  189. PmcCtl p;
  190. char *s;
  191. uint64_t v;
  192. uint64_t coreno;
  193. type = PMCTYPE(c->qid.path);
  194. id = PMCID(c->qid.path);
  195. switch(type){
  196. case Qcore:
  197. case Qdir:
  198. case Qctr:
  199. return devdirread(c, a, n, nil, 0, pmcgen);
  200. }
  201. s = malloc(PmcCtlRdStr);
  202. if(waserror()){
  203. free(s);
  204. nexterror();
  205. }
  206. coreno = (uint64_t)c->aux;
  207. p.coreno = coreno;
  208. switch(type){
  209. case Qdata:
  210. v = pmcgetctr(coreno, id);
  211. snprint(s, PmcCtlRdStr, "%#ullx", v);
  212. break;
  213. case Qctl:
  214. if (pmcgetctl(coreno, &p, id) < 0)
  215. error("bad ctr");
  216. if (pmcctlstr(s, PmcCtlRdStr, &p) < 0)
  217. error("bad pmc");
  218. break;
  219. case Qgctl:
  220. if (pmcdescstr(s, PmcCtlRdStr) < 0)
  221. error("bad pmc");
  222. break;
  223. default:
  224. error(Eperm);
  225. }
  226. n = readstr(offset, a, n, s);
  227. free(s);
  228. poperror();
  229. return n;
  230. }
  231. enum{
  232. Enable,
  233. Disable,
  234. User,
  235. Os,
  236. NoUser,
  237. NoOs,
  238. Reset,
  239. Debug,
  240. };
  241. static Cmdtab pmcctlmsg[] =
  242. {
  243. Enable, "enable", 0,
  244. Disable, "disable", 0,
  245. User, "user", 0,
  246. Os, "os", 0,
  247. NoUser, "nouser", 0,
  248. NoOs, "noos", 0,
  249. Reset, "reset", 0,
  250. Debug, "debug", 0,
  251. };
  252. typedef void (*APfunc)(void);
  253. typedef struct AcPmcArg AcPmcArg;
  254. struct AcPmcArg {
  255. int regno;
  256. int coreno;
  257. PmcCtl;
  258. };
  259. typedef struct AcCtrArg AcCtrArg;
  260. struct AcCtrArg {
  261. int regno;
  262. int coreno;
  263. uint64_t v;
  264. };
  265. void
  266. acpmcsetctl(void)
  267. {
  268. AcPmcArg p;
  269. Mach *mp;
  270. mp = up->ac;
  271. memmove(&p, mp->icc->data, sizeof(AcPmcArg));
  272. mp->icc->rc = pmcsetctl(p.coreno, &p, p.regno);
  273. return;
  274. }
  275. void
  276. acpmcsetctr(void)
  277. {
  278. AcCtrArg ctr;
  279. Mach *mp;
  280. mp = up->ac;
  281. memmove(&ctr, mp->icc->data, sizeof(AcCtrArg));
  282. mp->icc->rc = pmcsetctr(ctr.coreno, ctr.v, ctr.regno);
  283. return;
  284. }
  285. static int32_t
  286. pmcwrite(Chan *c, void *a, int32_t n, int64_t)
  287. {
  288. Cmdbuf *cb;
  289. Cmdtab *ct;
  290. uint32_t type;
  291. char str[64]; /* 0x0000000000000000\0 */
  292. AcPmcArg p;
  293. AcCtrArg ctr;
  294. uint64_t coreno;
  295. Mach *mp;
  296. if (c->qid.type == QTDIR)
  297. error(Eperm);
  298. if (c->qid.path == Qgctl)
  299. error(Eperm);
  300. if (n >= sizeof(str))
  301. error(Ebadctl);
  302. pmcnull(&p);
  303. coreno = (uint64_t)c->aux;
  304. p.coreno = coreno;
  305. type = PMCTYPE(c->qid.path);
  306. p.regno = PMCID(c->qid.path);
  307. memmove(str, a, n);
  308. str[n] = '\0';
  309. mp = up->ac;
  310. ctr.coreno = coreno;
  311. ctr.regno = p.regno;
  312. if (type == Qdata) {
  313. /* I am a handler for a proc in the core, run an RPC*/
  314. if (mp != nil && mp->machno == coreno) {
  315. if (runac(mp, acpmcsetctr, 0, &ctr, sizeof(AcCtrArg)) < 0)
  316. n = -1;
  317. } else {
  318. if (pmcsetctr(coreno, strtoull(str, 0, 0), p.regno) < 0)
  319. n = -1;
  320. }
  321. return n;
  322. }
  323. /* TODO: should iterate through multiple lines */
  324. if (strncmp(str, "set ", 4) == 0){
  325. memmove(p.descstr, (char *)str + 4, n - 4);
  326. p.descstr[n - 4] = '\0';
  327. p.nodesc = 0;
  328. } else {
  329. cb = parsecmd(a, n);
  330. if(waserror()){
  331. free(cb);
  332. nexterror();
  333. }
  334. ct = lookupcmd(cb, pmcctlmsg, nelem(pmcctlmsg));
  335. switch(ct->index){
  336. case Enable:
  337. p.enab = 1;
  338. break;
  339. case Disable:
  340. p.enab = 0;
  341. break;
  342. case User:
  343. p.user = 1;
  344. break;
  345. case Os:
  346. p.os = 1;
  347. break;
  348. case NoUser:
  349. p.user = 0;
  350. break;
  351. case NoOs:
  352. p.os = 0;
  353. break;
  354. case Reset:
  355. p.reset = 1;
  356. break;
  357. case Debug:
  358. pmcdebug = ~pmcdebug;
  359. break;
  360. default:
  361. cmderror(cb, "invalid ctl");
  362. break;
  363. }
  364. free(cb);
  365. poperror();
  366. }
  367. /* I am a handler for a proc in the core, run an RPC*/
  368. if (mp != nil && mp->machno == coreno) {
  369. if (runac(mp, acpmcsetctl, 0, &p, sizeof(AcPmcArg)) < 0)
  370. n = -1;
  371. } else {
  372. if (pmcsetctl(coreno, &p, p.regno) < 0)
  373. n = -1;
  374. }
  375. return n;
  376. }
  377. Dev pmcdevtab = {
  378. L'ε',
  379. "pmc",
  380. pmcinit,
  381. devinit,
  382. devshutdown,
  383. pmcattach,
  384. pmcwalk,
  385. pmcstat,
  386. pmcopen,
  387. devcreate,
  388. pmcclose,
  389. pmcread,
  390. devbread,
  391. pmcwrite,
  392. devbwrite,
  393. devremove,
  394. devwstat,
  395. };