devmem.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. #include "dat.h"
  2. #include "fns.h"
  3. #include "error.h"
  4. #include "interp.h"
  5. enum
  6. {
  7. Qdir,
  8. Qctl,
  9. Qstate,
  10. Qsum,
  11. Qevent,
  12. Qprof,
  13. Qheap,
  14. Qgc
  15. };
  16. static
  17. Dirtab memdir[] =
  18. {
  19. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  20. "memctl", {Qctl}, 0, 0666,
  21. "memstate", {Qstate}, 0, 0444,
  22. "memsum", {Qsum}, 0, 0444,
  23. "memevent", {Qevent}, 0, 0444,
  24. "memprof", {Qprof}, 0, 0444,
  25. "memheap", {Qheap}, 0, 0444,
  26. "memgc", {Qgc}, 0, 0444,
  27. };
  28. enum
  29. {
  30. /* these are the top two bits of size */
  31. Pflags= 3<<30,
  32. Pfree= 0<<30,
  33. Palloc= 1<<30,
  34. Paend= 2<<30,
  35. Pimmutable= 3<<30,
  36. Npool = 3,
  37. Nevent = 10000,
  38. Nstate = 12000
  39. };
  40. /*
  41. * pool snapshots
  42. */
  43. typedef struct Pstate Pstate;
  44. struct Pstate
  45. {
  46. ulong base;
  47. ulong size;
  48. };
  49. static struct
  50. {
  51. Pstate state[3+Nstate];
  52. Pstate* lim;
  53. Pstate* ptr;
  54. int summary;
  55. } poolstate[Npool];
  56. static Ref stateopen;
  57. /*
  58. * pool/heap allocation events
  59. */
  60. typedef struct Pevent Pevent;
  61. struct Pevent
  62. {
  63. int pool;
  64. ulong pc;
  65. ulong base;
  66. ulong size;
  67. };
  68. static struct
  69. {
  70. Lock l;
  71. Ref inuse;
  72. Rendez r;
  73. int open;
  74. Pevent events[Nevent];
  75. int rd;
  76. int wr;
  77. int full;
  78. int want;
  79. ulong lost;
  80. } poolevents;
  81. /*
  82. * allocation profiles
  83. */
  84. typedef struct Pprof Pprof;
  85. typedef struct Pbucket Pbucket;
  86. struct Pbucket
  87. {
  88. ulong val;
  89. ulong pool;
  90. ulong count;
  91. ulong size;
  92. Pbucket* next;
  93. };
  94. static struct {
  95. Ref inuse; /* only one of these things */
  96. Lock l;
  97. Pbucket buckets[1000];
  98. Pbucket snap[1000];
  99. int used;
  100. int snapped;
  101. Pbucket* hash[128];
  102. ulong lost;
  103. } memprof;
  104. extern void (*memmonitor)(int, ulong, ulong, ulong);
  105. extern ulong gcnruns;
  106. extern ulong gcsweeps;
  107. extern ulong gcbroken;
  108. extern ulong gchalted;
  109. extern ulong gcepochs;
  110. extern uvlong gcdestroys;
  111. extern uvlong gcinspects;
  112. extern uvlong gcbusy;
  113. extern uvlong gcidle;
  114. extern uvlong gcidlepass;
  115. extern uvlong gcpartial;
  116. static void
  117. mprofreset(void)
  118. {
  119. lock(&memprof.l); /* need ilock in kernel */
  120. memset(memprof.hash, 0, sizeof(memprof.hash));
  121. memprof.used = 0;
  122. memprof.lost = 0;
  123. unlock(&memprof.l);
  124. }
  125. static void
  126. mprofmonitor(int pool, ulong pc, ulong base, ulong size)
  127. {
  128. Pbucket **h0, **h, *p;
  129. if((pool&7) == 1)
  130. return; /* ignore heap */
  131. USED(base);
  132. h0 = &memprof.hash[((pc>>16)^(pc>>4))&(nelem(memprof.hash)-1)];
  133. lock(&memprof.l);
  134. for(h = h0; (p = *h) != nil; h = &p->next)
  135. if(p->val == pc && p->pool == pool){
  136. p->count++;
  137. p->size += size;
  138. *h = p->next;
  139. p->next = *h0;
  140. *h0 = p;
  141. unlock(&memprof.l);
  142. return;
  143. }
  144. if(memprof.used >= nelem(memprof.buckets)){
  145. memprof.lost++;
  146. unlock(&memprof.l);
  147. return;
  148. }
  149. p = &memprof.buckets[memprof.used++];
  150. p->val = pc;
  151. p->pool = pool;
  152. p->count = 1;
  153. p->size = size;
  154. p->next = *h0;
  155. *h0 = p;
  156. unlock(&memprof.l);
  157. }
  158. static void
  159. _memmonitor(int pool, ulong pc, ulong base, ulong size)
  160. {
  161. Pevent e;
  162. e.pool = pool;
  163. e.pc = pc;
  164. e.base = base;
  165. e.size = size;
  166. lock(&poolevents.l);
  167. if(!poolevents.full){
  168. poolevents.events[poolevents.wr] = e;
  169. if(++poolevents.wr == nelem(poolevents.events))
  170. poolevents.wr = 0;
  171. if(poolevents.wr == poolevents.rd)
  172. poolevents.full = 1;
  173. }else
  174. poolevents.lost++;
  175. if(poolevents.want){
  176. poolevents.want = 0;
  177. Wakeup(&poolevents.r);
  178. }
  179. unlock(&poolevents.l);
  180. }
  181. static int
  182. ismemdata(void *v)
  183. {
  184. USED(v);
  185. return poolevents.full || poolevents.rd != poolevents.wr;
  186. }
  187. static char*
  188. memaudit(int pno, Bhdr *b)
  189. {
  190. Pstate *p;
  191. if(pno >= Npool)
  192. return "too many pools for memaudit";
  193. if((p = poolstate[pno].ptr) == poolstate[pno].lim){
  194. if(b->magic == MAGIC_E)
  195. return nil;
  196. p = &poolstate[pno].state[1];
  197. if(b->magic == MAGIC_F)
  198. p++;
  199. p->base++;
  200. p->size += b->size;
  201. return nil;
  202. }
  203. poolstate[pno].ptr++;
  204. p->base = (ulong)b;
  205. p->size = b->size;
  206. switch(b->magic){
  207. case MAGIC_A:
  208. p->size |= Palloc;
  209. break;
  210. case MAGIC_F:
  211. p->size |= Pfree;
  212. break;
  213. case MAGIC_E:
  214. p->size = b->csize | Paend;
  215. break;
  216. case MAGIC_I:
  217. p->size |= Pimmutable;
  218. break;
  219. default:
  220. return "bad magic number in block";
  221. }
  222. return nil;
  223. }
  224. static void
  225. mput4(uchar *m, ulong v)
  226. {
  227. m[0] = v>>24;
  228. m[1] = v>>16;
  229. m[2] = v>>8;
  230. m[3] = v;
  231. }
  232. static Chan*
  233. memattach(char *spec)
  234. {
  235. return devattach('%', spec);
  236. }
  237. static Walkqid*
  238. memwalk(Chan *c, Chan *nc, char **name, int nname)
  239. {
  240. return devwalk(c, nc, name, nname, memdir, nelem(memdir), devgen);
  241. }
  242. static int
  243. memstat(Chan *c, uchar *db, int n)
  244. {
  245. return devstat(c, db, n, memdir, nelem(memdir), devgen);
  246. }
  247. static Chan*
  248. memopen(Chan *c, int omode)
  249. {
  250. if(memmonitor != nil && c->qid.path != Qgc)
  251. error(Einuse);
  252. c = devopen(c, omode, memdir, nelem(memdir), devgen);
  253. switch((ulong)c->qid.path){
  254. case Qevent:
  255. if(incref(&poolevents.inuse) != 1){
  256. decref(&poolevents.inuse);
  257. c->flag &= ~COPEN;
  258. error(Einuse);
  259. }
  260. poolevents.rd = poolevents.wr = 0;
  261. poolevents.full = 0;
  262. poolevents.want = 0;
  263. poolevents.lost = 0;
  264. memmonitor = _memmonitor;
  265. poolevents.open = 1;
  266. break;
  267. case Qstate:
  268. if(incref(&stateopen) != 1){
  269. decref(&stateopen);
  270. c->flag &= ~COPEN;
  271. error(Einuse);
  272. }
  273. break;
  274. case Qprof:
  275. if(incref(&memprof.inuse) != 1){
  276. decref(&memprof.inuse);
  277. c->flag &= ~COPEN;
  278. error(Einuse);
  279. }
  280. memmonitor = mprofmonitor;
  281. break;
  282. }
  283. return c;
  284. }
  285. static void
  286. memclose(Chan *c)
  287. {
  288. if((c->flag & COPEN) == 0)
  289. return;
  290. switch((ulong)c->qid.path) {
  291. case Qevent:
  292. memmonitor = nil;
  293. poolevents.open = 0;
  294. decref(&poolevents.inuse);
  295. break;
  296. case Qstate:
  297. decref(&stateopen);
  298. break;
  299. case Qprof:
  300. decref(&memprof.inuse);
  301. memmonitor = nil;
  302. break;
  303. }
  304. }
  305. static long
  306. memread(Chan *c, void *va, long count, vlong offset)
  307. {
  308. uchar *m;
  309. char *e, *s;
  310. int i, summary;
  311. long n, nr;
  312. Pstate *p;
  313. Pevent pe;
  314. Pbucket *b;
  315. if(c->qid.type & QTDIR)
  316. return devdirread(c, va, count, memdir, nelem(memdir), devgen);
  317. summary = 0;
  318. switch((ulong)c->qid.path) {
  319. default:
  320. error(Egreg);
  321. case Qctl:
  322. return 0;
  323. case Qsum:
  324. summary = 1;
  325. /* fall through */
  326. case Qstate:
  327. if(offset == 0){
  328. for(i=0; i<Npool; i++){
  329. poolstate[i].ptr = &poolstate[i].state[3];
  330. poolstate[i].lim = poolstate[i].ptr + Nstate;
  331. memset(poolstate[i].state, 0, sizeof(poolstate[i].state));
  332. poolstate[i].summary = summary;
  333. }
  334. e = poolaudit(memaudit);
  335. if(e != nil){
  336. print("mem: %s\n", e);
  337. error(e);
  338. }
  339. }
  340. m = va;
  341. nr = offset/8;
  342. for(i=0; i<Npool && count >= 8; i++){
  343. n = poolstate[i].ptr - poolstate[i].state;
  344. poolstate[i].state[0].base = i;
  345. poolstate[i].state[0].size = n;
  346. if(nr >= n){
  347. nr -= n;
  348. continue;
  349. }
  350. n -= nr;
  351. p = &poolstate[i].state[nr];
  352. for(; --n >= 0 && (count -= 8) >= 0; m += 8, p++){
  353. mput4(m, p->base);
  354. mput4(m+4, p->size);
  355. }
  356. }
  357. return m-(uchar*)va;
  358. case Qevent:
  359. while(!ismemdata(nil)){
  360. poolevents.want = 1;
  361. Sleep(&poolevents.r, ismemdata, nil);
  362. }
  363. m = va;
  364. do{
  365. if((count -= 4*4) < 0)
  366. return m-(uchar*)va;
  367. pe = poolevents.events[poolevents.rd];
  368. mput4(m, pe.pool);
  369. mput4(m+4, pe.pc);
  370. mput4(m+8, pe.base);
  371. mput4(m+12, pe.size);
  372. m += 4*4;
  373. if(++poolevents.rd >= nelem(poolevents.events))
  374. poolevents.rd = 0;
  375. }while(poolevents.rd != poolevents.wr);
  376. poolevents.full = 0;
  377. return m-(uchar*)va;
  378. case Qprof:
  379. if(offset == 0){
  380. lock(&memprof.l);
  381. memmove(memprof.snap, memprof.buckets, memprof.used*sizeof(memprof.buckets[0]));
  382. memprof.snapped = memprof.used;
  383. unlock(&memprof.l);
  384. }
  385. m = va;
  386. for(i = offset/(4*4); i < memprof.snapped && (count -= 4*4) >= 0; i++){
  387. b = &memprof.snap[i];
  388. mput4(m, b->pool);
  389. mput4(m+4, b->val);
  390. mput4(m+8, b->count);
  391. mput4(m+12, b->size);
  392. m += 4*4;
  393. }
  394. return m-(uchar*)va;
  395. case Qgc:
  396. s = malloc(READSTR);
  397. if(s == nil)
  398. error(Enomem);
  399. if(waserror()){
  400. free(s);
  401. nexterror();
  402. }
  403. 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",
  404. gcnruns, gcsweeps, gcbroken, gchalted, gcepochs, gcdestroys, gcinspects, gcbusy, gcidle, gcidlepass, gcpartial);
  405. count = readstr(offset, va, count, s);
  406. poperror();
  407. free(s);
  408. return count;
  409. }
  410. }
  411. static long
  412. memwrite(Chan *c, void *va, long count, vlong offset)
  413. {
  414. USED(offset);
  415. USED(count);
  416. USED(va);
  417. if(c->qid.type & QTDIR)
  418. error(Eperm);
  419. switch((ulong)c->qid.path) {
  420. default:
  421. error(Egreg);
  422. case Qctl:
  423. error(Ebadarg);
  424. case Qstate:
  425. error(Eperm);
  426. case Qprof:
  427. mprofreset();
  428. break;
  429. }
  430. return 0;
  431. }
  432. Dev memdevtab = {
  433. '%',
  434. "mem",
  435. devinit,
  436. memattach,
  437. memwalk,
  438. memstat,
  439. memopen,
  440. devcreate,
  441. memclose,
  442. memread,
  443. devbread,
  444. memwrite,
  445. devbwrite,
  446. devremove,
  447. devwstat
  448. };