profile.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <tos.h>
  4. extern long _callpc(void**);
  5. extern long _savearg(void);
  6. ulong khz;
  7. ulong perr;
  8. uvlong cyclefreq;
  9. int havecycles;
  10. typedef struct Plink Plink;
  11. struct Plink
  12. {
  13. Plink *old;
  14. Plink *down;
  15. Plink *link;
  16. long pc;
  17. long count;
  18. vlong time;
  19. };
  20. #pragma profile off
  21. ulong
  22. _profin(void)
  23. {
  24. void *dummy;
  25. long pc;
  26. Plink *pp, *p;
  27. ulong arg;
  28. vlong t;
  29. arg = _savearg();
  30. pc = _callpc(&dummy);
  31. pp = _tos->prof.pp;
  32. if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid))
  33. return arg;
  34. for(p=pp->down; p; p=p->link)
  35. if(p->pc == pc)
  36. goto out;
  37. p = _tos->prof.next + 1;
  38. if(p >= _tos->prof.last) {
  39. _tos->prof.pp = 0;
  40. perr++;
  41. return arg;
  42. }
  43. _tos->prof.next = p;
  44. p->link = pp->down;
  45. pp->down = p;
  46. p->pc = pc;
  47. p->old = pp;
  48. p->down = 0;
  49. p->count = 0;
  50. p->time = 0LL;
  51. out:
  52. _tos->prof.pp = p;
  53. p->count++;
  54. switch(_tos->prof.what){
  55. case Profkernel:
  56. p->time = p->time - _tos->pcycles;
  57. goto proftime;
  58. case Profuser:
  59. /* Add kernel cycles on proc entry */
  60. p->time = p->time + _tos->kcycles;
  61. /* fall through */
  62. case Proftime:
  63. proftime: /* Subtract cycle counter on proc entry */
  64. cycles((uvlong*)&t);
  65. p->time = p->time - t;
  66. break;
  67. case Profsample:
  68. p->time = p->time - _tos->clock;
  69. break;
  70. }
  71. return arg; /* disgusting linkage */
  72. }
  73. ulong
  74. _profout(void)
  75. {
  76. Plink *p;
  77. ulong arg;
  78. vlong t;
  79. arg = _savearg();
  80. p = _tos->prof.pp;
  81. if (p == nil || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid))
  82. return arg; /* Not our process */
  83. switch(_tos->prof.what){
  84. case Profkernel: /* Add proc cycles on proc entry */
  85. p->time = p->time + _tos->pcycles;
  86. goto proftime;
  87. case Profuser: /* Subtract kernel cycles on proc entry */
  88. p->time = p->time - _tos->kcycles;
  89. /* fall through */
  90. case Proftime:
  91. proftime: /* Add cycle counter on proc entry */
  92. cycles((uvlong*)&t);
  93. p->time = p->time + t;
  94. break;
  95. case Profsample:
  96. p->time = p->time + _tos->clock;
  97. break;
  98. }
  99. _tos->prof.pp = p->old;
  100. return arg;
  101. }
  102. void
  103. _profdump(void)
  104. {
  105. int f;
  106. long n;
  107. Plink *p;
  108. char *vp;
  109. char filename[64];
  110. if (_tos->prof.what == 0)
  111. return; /* No profiling */
  112. if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)
  113. return; /* Not our process */
  114. if(perr)
  115. fprint(2, "%lud Prof errors\n", perr);
  116. _tos->prof.pp = nil;
  117. if (_tos->prof.pid)
  118. snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid);
  119. else
  120. snprint(filename, sizeof filename - 1, "prof.out");
  121. f = create(filename, 1, 0666);
  122. if(f < 0) {
  123. perror("create prof.out");
  124. return;
  125. }
  126. _tos->prof.pid = ~0; /* make sure data gets dumped once */
  127. switch(_tos->prof.what){
  128. case Profkernel:
  129. cycles((uvlong*)&_tos->prof.first->time);
  130. _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles;
  131. break;
  132. case Profuser:
  133. cycles((uvlong*)&_tos->prof.first->time);
  134. _tos->prof.first->time = _tos->prof.first->time + _tos->kcycles;
  135. break;
  136. case Proftime:
  137. cycles((uvlong*)&_tos->prof.first->time);
  138. break;
  139. case Profsample:
  140. _tos->prof.first->time = _tos->clock;
  141. break;
  142. }
  143. vp = (char*)_tos->prof.first;
  144. for(p = _tos->prof.first; p <= _tos->prof.next; p++) {
  145. /*
  146. * short down
  147. */
  148. n = 0xffff;
  149. if(p->down)
  150. n = p->down - _tos->prof.first;
  151. vp[0] = n>>8;
  152. vp[1] = n;
  153. /*
  154. * short right
  155. */
  156. n = 0xffff;
  157. if(p->link)
  158. n = p->link - _tos->prof.first;
  159. vp[2] = n>>8;
  160. vp[3] = n;
  161. vp += 4;
  162. /*
  163. * long pc
  164. */
  165. n = p->pc;
  166. vp[0] = n>>24;
  167. vp[1] = n>>16;
  168. vp[2] = n>>8;
  169. vp[3] = n;
  170. vp += 4;
  171. /*
  172. * long count
  173. */
  174. n = p->count;
  175. vp[0] = n>>24;
  176. vp[1] = n>>16;
  177. vp[2] = n>>8;
  178. vp[3] = n;
  179. vp += 4;
  180. /*
  181. * vlong time
  182. */
  183. if (havecycles){
  184. n = (vlong)(p->time / (vlong)khz);
  185. }else
  186. n = p->time;
  187. vp[0] = n>>24;
  188. vp[1] = n>>16;
  189. vp[2] = n>>8;
  190. vp[3] = n;
  191. vp += 4;
  192. }
  193. write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first);
  194. close(f);
  195. }
  196. void
  197. _profinit(int entries, int what)
  198. {
  199. if (_tos->prof.what == 0)
  200. return; /* Profiling not linked in */
  201. _tos->prof.pp = nil;
  202. _tos->prof.first = mallocz(entries*sizeof(Plink),1);
  203. _tos->prof.last = _tos->prof.first + entries;
  204. _tos->prof.next = _tos->prof.first;
  205. _tos->prof.pid = _tos->pid;
  206. _tos->prof.what = what;
  207. _tos->clock = 1;
  208. }
  209. void
  210. _profmain(void)
  211. {
  212. char ename[50];
  213. int n, f;
  214. n = 2000;
  215. if (_tos->cyclefreq != 0LL){
  216. khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */
  217. havecycles = 1;
  218. }
  219. f = open("/env/profsize", OREAD);
  220. if(f >= 0) {
  221. memset(ename, 0, sizeof(ename));
  222. read(f, ename, sizeof(ename)-1);
  223. close(f);
  224. n = atol(ename);
  225. }
  226. _tos->prof.what = Profuser;
  227. f = open("/env/proftype", OREAD);
  228. if(f >= 0) {
  229. memset(ename, 0, sizeof(ename));
  230. read(f, ename, sizeof(ename)-1);
  231. close(f);
  232. if (strcmp(ename, "user") == 0)
  233. _tos->prof.what = Profuser;
  234. else if (strcmp(ename, "kernel") == 0)
  235. _tos->prof.what = Profkernel;
  236. else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0)
  237. _tos->prof.what = Proftime;
  238. else if (strcmp(ename, "sample") == 0)
  239. _tos->prof.what = Profsample;
  240. }
  241. _tos->prof.first = sbrk(n*sizeof(Plink));
  242. _tos->prof.last = sbrk(0);
  243. _tos->prof.next = _tos->prof.first;
  244. _tos->prof.pp = nil;
  245. _tos->prof.pid = _tos->pid;
  246. atexit(_profdump);
  247. _tos->clock = 1;
  248. }
  249. void prof(void (*fn)(void*), void *arg, int entries, int what)
  250. {
  251. _profinit(entries, what);
  252. _tos->prof.pp = _tos->prof.next;
  253. fn(arg);
  254. _profdump();
  255. }
  256. #pragma profile on