profile.c 5.3 KB

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