devprof.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. #include "dat.h"
  2. #include "fns.h"
  3. #include "error.h"
  4. #include "interp.h"
  5. #include <isa.h>
  6. #include "runt.h"
  7. extern Pool* imagmem;
  8. extern void (*memmonitor)(int, ulong, ulong, ulong);
  9. static void cpxec(Prog *);
  10. static void memprof(int, void*, ulong);
  11. static void memprofmi(int, ulong, ulong, ulong);
  12. extern Inst* pc2dispc(Inst*, Module*);
  13. static int interval = 100; /* Sampling interval in milliseconds */
  14. enum
  15. {
  16. HSIZE = 32,
  17. };
  18. #define HASH(m) ((m)%HSIZE)
  19. /* cope with multiple profilers some day */
  20. typedef struct Record Record;
  21. struct Record
  22. {
  23. int id;
  24. char* name;
  25. char* path;
  26. Inst* base;
  27. int size;
  28. /*Module* m; */
  29. ulong mtime;
  30. Qid qid;
  31. Record* hash;
  32. Record* link;
  33. ulong bucket[1];
  34. };
  35. struct
  36. {
  37. Lock l;
  38. vlong time;
  39. Record* hash[HSIZE];
  40. Record* list;
  41. } profile;
  42. typedef struct Pmod Pmod;
  43. struct Pmod
  44. {
  45. char* name;
  46. Pmod* link;
  47. } *pmods;
  48. #define QSHIFT 4
  49. #define QID(q) ((ulong)(q).path&0xf)
  50. #define QPID(pid) ((pid)<<QSHIFT)
  51. #define PID(q) ((q).vers)
  52. #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1))
  53. enum
  54. {
  55. Qdir,
  56. Qname,
  57. Qpath,
  58. Qhist,
  59. Qpctl,
  60. Qctl,
  61. };
  62. Dirtab profdir[] =
  63. {
  64. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  65. "name", {Qname}, 0, 0444,
  66. "path", {Qpath}, 0, 0444,
  67. "histogram", {Qhist}, 0, 0444,
  68. "pctl", {Qpctl}, 0, 0222,
  69. "ctl", {Qctl}, 0, 0222,
  70. };
  71. enum{
  72. Pnil, /* null profiler */
  73. Psam, /* sampling profiler */
  74. Pcov, /* coverage profiler */
  75. Pmem, /* heap memory profiler */
  76. };
  77. enum{
  78. Mnone = 0,
  79. Mmain = 1,
  80. Mheap = 2,
  81. Mimage = 4,
  82. };
  83. static int profiler = Pnil;
  84. static int mprofiler = Mnone;
  85. static int ids;
  86. static int samplefn;
  87. static void sampler(void*);
  88. static Record*
  89. getrec(int id)
  90. {
  91. Record *r;
  92. for(r = profile.list; r != nil; r = r->link)
  93. if(r->id == id)
  94. break;
  95. return r;
  96. }
  97. static void
  98. addpmod(char *m)
  99. {
  100. Pmod *p = malloc(sizeof(Pmod));
  101. if(p == nil)
  102. return;
  103. p->name = malloc(strlen(m)+1);
  104. if(p->name == nil){
  105. free(p);
  106. return;
  107. }
  108. strcpy(p->name, m);
  109. p->link = pmods;
  110. pmods = p;
  111. }
  112. static void
  113. freepmods(void)
  114. {
  115. Pmod *p, *np;
  116. for(p = pmods; p != nil; p = np){
  117. free(p->name);
  118. np = p->link;
  119. free(p);
  120. }
  121. pmods = nil;
  122. }
  123. static int
  124. inpmods(char *m)
  125. {
  126. Pmod *p;
  127. for(p = pmods; p != nil; p = p->link)
  128. if(strcmp(p->name, m) == 0)
  129. return 1;
  130. return 0;
  131. }
  132. static void
  133. freeprof(void)
  134. {
  135. int i;
  136. Record *r, *nr;
  137. ids = 0;
  138. profiler = Pnil;
  139. mprofiler = Mnone;
  140. freepmods();
  141. for(r = profile.list; r != nil; r = nr){
  142. free(r->name);
  143. free(r->path);
  144. nr = r->link;
  145. free(r);
  146. }
  147. profile.list = nil;
  148. profile.time = 0;
  149. for(i = 0; i < HSIZE; i++)
  150. profile.hash[i] = nil;
  151. }
  152. static int
  153. profgen(Chan *c, char *name, Dirtab *d, int nd, int s, Dir *dp)
  154. {
  155. Qid qid;
  156. Record *r;
  157. ulong path, perm, len;
  158. Dirtab *tab;
  159. USED(name);
  160. USED(d);
  161. USED(nd);
  162. if(s == DEVDOTDOT) {
  163. mkqid(&qid, Qdir, 0, QTDIR);
  164. devdir(c, qid, "#P", 0, eve, 0555, dp);
  165. return 1;
  166. }
  167. if(c->qid.path == Qdir && c->qid.type & QTDIR) {
  168. acquire();
  169. if(s-- == 0){
  170. tab = &profdir[Qctl];
  171. mkqid(&qid, PATH(c->qid)|tab->qid.path, c->qid.vers, QTFILE);
  172. devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
  173. release();
  174. return 1;
  175. }
  176. r = profile.list;
  177. while(s-- && r != nil)
  178. r = r->link;
  179. if(r == nil) {
  180. release();
  181. return -1;
  182. }
  183. sprint(up->genbuf, "%.8lux", (ulong)r->id);
  184. mkqid(&qid, (r->id<<QSHIFT), r->id, QTDIR);
  185. devdir(c, qid, up->genbuf, 0, eve, DMDIR|0555, dp);
  186. release();
  187. return 1;
  188. }
  189. if(s >= nelem(profdir)-1)
  190. error(Enonexist); /* was return -1; */
  191. tab = &profdir[s];
  192. path = PATH(c->qid);
  193. acquire();
  194. r = getrec(PID(c->qid));
  195. if(r == nil) {
  196. release();
  197. error(Enonexist); /* was return -1; */
  198. }
  199. perm = tab->perm;
  200. len = tab->length;
  201. mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
  202. devdir(c, qid, tab->name, len, eve, perm, dp);
  203. release();
  204. return 1;
  205. }
  206. static Chan*
  207. profattach(char *spec)
  208. {
  209. return devattach('P', spec);
  210. }
  211. static Walkqid*
  212. profwalk(Chan *c, Chan *nc, char **name, int nname)
  213. {
  214. return devwalk(c, nc, name, nname, 0, 0, profgen);
  215. }
  216. static int
  217. profstat(Chan *c, uchar *db, int n)
  218. {
  219. return devstat(c, db, n, 0, 0, profgen);
  220. }
  221. static Chan*
  222. profopen(Chan *c, int omode)
  223. {
  224. int qid;
  225. Record *r;
  226. if(c->qid.type & QTDIR) {
  227. if(omode != OREAD)
  228. error(Eisdir);
  229. c->mode = openmode(omode);
  230. c->flag |= COPEN;
  231. c->offset = 0;
  232. return c;
  233. }
  234. if(omode&OTRUNC)
  235. error(Eperm);
  236. qid = QID(c->qid);
  237. if(qid == Qctl || qid == Qpctl){
  238. if (omode != OWRITE)
  239. error(Eperm);
  240. }
  241. else{
  242. if(omode != OREAD)
  243. error(Eperm);
  244. }
  245. if(qid != Qctl){
  246. acquire();
  247. r = getrec(PID(c->qid));
  248. release();
  249. if(r == nil)
  250. error(Ethread);
  251. }
  252. c->offset = 0;
  253. c->flag |= COPEN;
  254. c->mode = openmode(omode);
  255. if(QID(c->qid) == Qhist)
  256. c->aux = nil;
  257. return c;
  258. }
  259. static int
  260. profwstat(Chan *c, uchar *dp, int n)
  261. {
  262. Dir d;
  263. Record *r;
  264. if(strcmp(up->env->user, eve))
  265. error(Eperm);
  266. if(c->qid.type & QTDIR)
  267. error(Eperm);
  268. acquire();
  269. r = getrec(PID(c->qid));
  270. release();
  271. if(r == nil)
  272. error(Ethread);
  273. n = convM2D(dp, n, &d, nil);
  274. if(n == 0)
  275. error(Eshortstat);
  276. d.mode &= 0777;
  277. /* TO DO: copy to c->aux->perm, once that exists */
  278. return n;
  279. }
  280. static void
  281. profclose(Chan *c)
  282. {
  283. USED(c);
  284. }
  285. static long
  286. profread(Chan *c, void *va, long n, vlong offset)
  287. {
  288. int i;
  289. Record *r;
  290. char *a = va;
  291. if(c->qid.type & QTDIR)
  292. return devdirread(c, a, n, 0, 0, profgen);
  293. acquire();
  294. r = getrec(PID(c->qid));
  295. release();
  296. if(r == nil)
  297. error(Ethread);
  298. switch(QID(c->qid)){
  299. case Qname:
  300. return readstr(offset, va, n, r->name);
  301. case Qpath:
  302. return readstr(offset, va, n, r->path);
  303. case Qhist:
  304. i = (int)c->aux;
  305. while(i < r->size && r->bucket[i] == 0)
  306. i++;
  307. if(i >= r->size)
  308. return 0;
  309. c->aux = (void*)(i+1);
  310. if(n < 20)
  311. error(Etoosmall);
  312. return sprint(a, "%d %lud", i, r->bucket[i]);
  313. case Qctl:
  314. error(Eperm);
  315. }
  316. return 0;
  317. }
  318. static long
  319. profwrite(Chan *c, void *va, long n, vlong offset)
  320. {
  321. int i;
  322. char *a = va;
  323. char buf[128], *fields[128];
  324. void (*f)(int, ulong, ulong, ulong);
  325. USED(va);
  326. USED(n);
  327. USED(offset);
  328. if(c->qid.type & QTDIR)
  329. error(Eisdir);
  330. switch(QID(c->qid)){
  331. case Qctl:
  332. if(n > sizeof(buf)-1)
  333. n = sizeof(buf)-1;
  334. memmove(buf, a, n);
  335. buf[n] = 0;
  336. i = getfields(buf, fields, nelem(fields), 1, " \t\n");
  337. if(i > 0 && strcmp(fields[0], "module") == 0){
  338. f = memmonitor;
  339. memmonitor = nil;
  340. freepmods();
  341. while(--i > 0)
  342. addpmod(fields[i]);
  343. memmonitor = f;
  344. return n;
  345. }
  346. if(i == 1){
  347. if(strcmp(fields[0], "start") == 0){
  348. if(profiler == Pnil) {
  349. profiler = Psam;
  350. if(!samplefn){
  351. samplefn = 1;
  352. kproc("prof", sampler, 0, 0);
  353. }
  354. }
  355. }
  356. else if(strncmp(fields[0], "startmp", 7) == 0){
  357. if(profiler == Pnil){
  358. profiler = Pmem;
  359. for(a = &fields[0][7]; *a != '\0'; a++){
  360. if(*a == '1'){
  361. memmonitor = memprofmi;
  362. mprofiler |= Mmain;
  363. }
  364. else if(*a == '2'){
  365. heapmonitor = memprof;
  366. mprofiler |= Mheap;
  367. }
  368. else if(*a == '3'){
  369. memmonitor = memprofmi;
  370. mprofiler |= Mimage;
  371. }
  372. };
  373. }
  374. }
  375. else if(strcmp(fields[0], "stop") == 0){
  376. profiler = Pnil;
  377. mprofiler = Mnone;
  378. }
  379. else if(strcmp(fields[0], "end") == 0){
  380. profiler = Pnil;
  381. mprofiler = Mnone;
  382. memmonitor = nil;
  383. freeprof();
  384. interval = 100;
  385. }
  386. else
  387. error(Ebadarg);
  388. }
  389. else if (i == 2){
  390. if(strcmp(fields[0], "interval") == 0)
  391. interval = strtoul(fields[1], nil, 0);
  392. else if(strcmp(fields[0], "startcp") == 0){
  393. Prog *p;
  394. acquire();
  395. p = progpid(strtoul(fields[1], nil, 0));
  396. if(p == nil){
  397. release();
  398. return -1;
  399. }
  400. if(profiler == Pnil){
  401. profiler = Pcov;
  402. p->xec = cpxec;
  403. }
  404. release();
  405. }
  406. else
  407. error(Ebadarg);
  408. }
  409. else
  410. error(Ebadarg);
  411. return n;
  412. default:
  413. error(Eperm);
  414. }
  415. return 0;
  416. }
  417. static Record*
  418. newmodule(Module *m, int vm, int scale, int origin)
  419. {
  420. int dsize;
  421. Record *r, **l;
  422. if(!vm)
  423. acquire();
  424. if((m->compiled && m->pctab == nil) || m->prog == nil) {
  425. if(!vm)
  426. release();
  427. return nil;
  428. }
  429. if(m->compiled)
  430. dsize = m->nprog * sizeof(r->bucket[0]);
  431. else
  432. dsize = (msize(m->prog)/sizeof(Inst)) * sizeof(r->bucket[0]);
  433. dsize *= scale;
  434. dsize += origin;
  435. r = malloc(sizeof(Record)+dsize);
  436. if(r == nil) {
  437. if(!vm)
  438. release();
  439. return nil;
  440. }
  441. r->id = ++ids;
  442. if(ids == (1<<8)-1)
  443. ids = 0;
  444. kstrdup(&r->name, m->name);
  445. kstrdup(&r->path, m->path);
  446. r->base = m->prog;
  447. r->size = dsize/sizeof(r->bucket[0]);
  448. /* r->m = m; */
  449. r->mtime = m->mtime;
  450. r->qid.path = m->qid.path;
  451. r->qid.vers = m->qid.vers;
  452. memset(r->bucket, 0, dsize);
  453. r->link = profile.list;
  454. profile.list = r;
  455. l = &profile.hash[HASH(m->mtime)];
  456. r->hash = *l;
  457. *l = r;
  458. if(!vm)
  459. release();
  460. return r;
  461. }
  462. #define LIMBO(m) ((m)->path[0] != '$')
  463. Module*
  464. limbomodule(void)
  465. {
  466. Frame *f;
  467. uchar *fp;
  468. Module *m;
  469. m = R.M->m;
  470. if(LIMBO(m))
  471. return m;
  472. for(fp = R.FP ; fp != nil; fp = f->fp){
  473. f = (Frame*)fp;
  474. if(f->mr != nil){
  475. m = f->mr->m;
  476. if(LIMBO(m))
  477. return m;
  478. }
  479. }
  480. return nil;
  481. }
  482. static Record*
  483. mlook(Module *m, int limbo, int vm, int scale, int origin)
  484. {
  485. Record *r;
  486. void (*f)(int, ulong, ulong, ulong);
  487. if(limbo)
  488. m = limbomodule();
  489. if(m == nil)
  490. return nil;
  491. for(r = profile.hash[HASH(m->mtime)]; r; r = r->hash){
  492. if(r->mtime == m->mtime && r->qid.path == m->qid.path && r->qid.vers == m->qid.vers && strcmp(r->name, m->name) == 0 && strcmp(r->path, m->path) == 0){
  493. r->base = m->prog;
  494. return r;
  495. }
  496. }
  497. if(pmods == nil || inpmods(m->name) || inpmods(m->path)){
  498. f = memmonitor;
  499. memmonitor = nil; /* prevent monitoring of our memory usage */
  500. r = newmodule(m, vm, scale, origin);
  501. memmonitor = f;
  502. return r;
  503. }
  504. return nil;
  505. }
  506. static void
  507. sampler(void* a)
  508. {
  509. int i;
  510. Module *m;
  511. Record *r;
  512. Inst *p;
  513. USED(a);
  514. for(;;) {
  515. osmillisleep(interval);
  516. if(profiler != Psam)
  517. break;
  518. lock(&profile.l);
  519. profile.time += interval;
  520. if(R.M == H || (m = R.M->m) == nil){
  521. unlock(&profile.l);
  522. continue;
  523. }
  524. p = R.PC;
  525. r = mlook(m, 0, 0, 1, 0);
  526. if(r == nil){
  527. unlock(&profile.l);
  528. continue;
  529. }
  530. if(m->compiled && m->pctab != nil)
  531. p = pc2dispc(p, m);
  532. if((i = p-r->base) >= 0 && i < r->size)
  533. r->bucket[i]++;
  534. unlock(&profile.l);
  535. }
  536. samplefn = 0;
  537. pexit("", 0);
  538. }
  539. /*
  540. * coverage profiling
  541. */
  542. static void
  543. cpxec(Prog *p)
  544. {
  545. int op, i;
  546. Module *m;
  547. Record *r;
  548. Prog *n;
  549. R = p->R;
  550. R.MP = R.M->MP;
  551. R.IC = p->quanta;
  552. if(p->kill != nil){
  553. char *m;
  554. m = p->kill;
  555. p->kill = nil;
  556. error(m);
  557. }
  558. if(R.M->compiled)
  559. comvec();
  560. else{
  561. m = R.M->m;
  562. r = profiler == Pcov ? mlook(m, 0, 1, 1, 0) : nil;
  563. do{
  564. dec[R.PC->add]();
  565. op = R.PC->op;
  566. if(r != nil){
  567. i = R.PC-r->base;
  568. if(i >= 0 && i < r->size)
  569. r->bucket[i]++;
  570. }
  571. R.PC++;
  572. optab[op]();
  573. if(op == ISPAWN || op == IMSPAWN){
  574. n = delruntail(Pdebug); /* any state will do */
  575. n->xec = cpxec;
  576. addrun(n);
  577. }
  578. if(m != R.M->m){
  579. m = R.M->m;
  580. r = profiler == Pcov ? mlook(m, 0, 1, 1, 0) : nil;
  581. }
  582. }while(--R.IC != 0);
  583. }
  584. p->R = R;
  585. }
  586. /* memory profiling */
  587. enum{
  588. Mhalloc,
  589. Mhfree,
  590. Mgcfree,
  591. Mmfree,
  592. Mmalloc,
  593. Mifree,
  594. Mialloc,
  595. };
  596. static void
  597. memprof(int c, void *v, ulong n)
  598. {
  599. int i, j, k;
  600. ulong kk, *b;
  601. Module *m;
  602. Record *r;
  603. Inst *p;
  604. Heap *h;
  605. USED(v);
  606. USED(n);
  607. if(profiler != Pmem){
  608. memmonitor = nil;
  609. heapmonitor = nil;
  610. return;
  611. }
  612. lock(&profile.l);
  613. m = nil;
  614. if(c != Mgcfree && (R.M == H || (m = R.M->m) == nil)){
  615. unlock(&profile.l);
  616. return;
  617. }
  618. h = v;
  619. if(c == Mhalloc || c == Mmalloc || c == Mialloc){
  620. p = R.PC;
  621. if(m->compiled && m->pctab != nil)
  622. p = pc2dispc(p, m);
  623. if((r = mlook(m, 1, 1, 2, 2)) == nil){
  624. unlock(&profile.l);
  625. return;
  626. }
  627. i = p-r->base;
  628. k = (r->id<<24) | i;
  629. if(c == Mhalloc){
  630. h->hprof = k;
  631. j = hmsize(h)-sizeof(Heap);
  632. }
  633. else if(c == Mmalloc){
  634. setmalloctag(v, k);
  635. j = msize(v);
  636. }
  637. else{
  638. ((ulong*)v)[1] = k;
  639. j = poolmsize(imagmem, v)-sizeof(ulong);
  640. }
  641. }
  642. else{
  643. if(c == Mmfree)
  644. k = getmalloctag(v);
  645. else if(c == Mifree)
  646. k = ((ulong*)v)[1];
  647. else
  648. k = h->hprof;
  649. if((r = getrec(k>>24)) == nil){
  650. unlock(&profile.l);
  651. return;
  652. }
  653. i = k&0xffffff;
  654. if(c == Mmfree)
  655. j = msize(v);
  656. else if(c == Mifree)
  657. j = poolmsize(imagmem, v)-sizeof(ulong);
  658. else
  659. j = hmsize(h)-sizeof(Heap);
  660. j = -j;
  661. }
  662. i = 2*(i+1);
  663. b = r->bucket;
  664. if(i >= 0 && i < r->size){
  665. if(0){
  666. if(c == 1){
  667. b[0] -= j;
  668. b[i] -= j;
  669. }
  670. else if(c == 2){
  671. b[1] -= j;
  672. b[i+1] -= j;
  673. }
  674. }
  675. else{
  676. b[0] += j;
  677. if((int)b[0] < 0)
  678. b[0] = 0;
  679. b[i] += j;
  680. if((int)b[i] < 0)
  681. b[i] = 0;
  682. if(j > 0){
  683. if((kk = b[0]) > b[1])
  684. b[1] = kk;
  685. if((kk = b[i]) > b[i+1])
  686. b[i+1] = kk;
  687. }
  688. }
  689. }
  690. unlock(&profile.l);
  691. }
  692. /* main and image memory */
  693. static void
  694. memprofmi(int c, ulong pc, ulong v, ulong n)
  695. {
  696. USED(pc);
  697. if(c&2){
  698. if(!(mprofiler&Mimage))
  699. return;
  700. }
  701. else{
  702. if(!(mprofiler&Mmain))
  703. return;
  704. }
  705. switch(c){
  706. case 0:
  707. c = Mmalloc;
  708. break;
  709. case 2:
  710. c = Mialloc;
  711. break;
  712. case 0 | 1<<8:
  713. c = Mmfree;
  714. break;
  715. case 2 | 1<<8:
  716. c = Mifree;
  717. break;
  718. default:
  719. print("bad profile code %d\n", c);
  720. }
  721. memprof(c, (void*)v, n);
  722. }
  723. Dev profdevtab = {
  724. 'P',
  725. "prof",
  726. devinit,
  727. profattach,
  728. profwalk,
  729. profstat,
  730. profopen,
  731. devcreate,
  732. profclose,
  733. profread,
  734. devbread,
  735. profwrite,
  736. devbwrite,
  737. devremove,
  738. profwstat
  739. };