tracer.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /*
  2. * Copyright (C) 2000-2004 by ETH Zurich
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
  21. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.btnode.ethz.ch
  31. *
  32. */
  33. /*
  34. * os/tracer.c
  35. *
  36. * 22.12.2004 Philipp Blum <blum@tik.ee.ethz.ch>
  37. *
  38. * \brief Routines to capture traces of nutOS programs
  39. * \note Only supported on AVR-GCC platform
  40. *
  41. */
  42. #if defined(__GNUC__) && defined(__AVR__)
  43. /************************************************/
  44. /* includes */
  45. /************************************************/
  46. #include <sys/tracer.h> // t_traceitem, t_trace
  47. #include <sys/heap.h> // NutHeapAlloc
  48. #include <sys/timer.h> // NutGetMillis
  49. #include <sys/thread.h> // NUTTHREADINFO
  50. #include <sys/atom.h> // NutEnterCritical_notrace
  51. #include <dev/irqreg.h> // sig_OVERFLOW1
  52. #include <stdio.h> // printf, sscanf
  53. #include <string.h> // strcmp
  54. /************************************************/
  55. /* global variables */
  56. /************************************************/
  57. unsigned int micros_high = 0;
  58. t_traceitem *trace_items = 0;
  59. t_traceitem *trace_current = 0;
  60. int trace_head = 0;
  61. int trace_size = 0;
  62. char trace_isfull = 0;
  63. char trace_isinit = 0;
  64. char trace_mode = TRACE_MODE_OFF;
  65. char trace_mask[TRACE_TAG_LAST+1] = {
  66. 0,
  67. 0,
  68. 1,
  69. 1,
  70. 1,
  71. 1,
  72. 0,
  73. 0,
  74. 1,
  75. 1,
  76. 1
  77. };
  78. char* tag_string[TRACE_TAG_LAST+1] = {
  79. "Critical Enter",
  80. "Critical Exit",
  81. "Thread Yield",
  82. "Thread SetPrio",
  83. "Thread Wait",
  84. "Thread Sleep",
  85. "Interrupt Enter",
  86. "Interrupt Exit",
  87. "Trace Start",
  88. "Trace Stop",
  89. "User *"
  90. };
  91. char* int_string[TRACE_INT_LAST+1] = {
  92. "UART0_CTS",
  93. "UART0_RXCOMPL",
  94. "UART0_TXEMPTY",
  95. "UART1_CTS",
  96. "UART1_RXCOMPL",
  97. "UART1_TXEMPTY",
  98. "TIMER0_OVERFL",
  99. "TIMER1_OVERFL",
  100. "SUART_TIMER",
  101. "SUART_RX"
  102. };
  103. char* mode_string[TRACE_MODE_LAST+1] = {
  104. "OFF",
  105. "CIRCULAR",
  106. "ONESHOT"
  107. };
  108. char* user_string[TRACE_MAX_USER];
  109. /************************************************/
  110. /* function definitions */
  111. /************************************************/
  112. static void NutTraceTimer1IRQ(void *arg)
  113. {
  114. // TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_ENTER,TRACE_INT_TIMER1_OVERFL);
  115. micros_high++;
  116. // TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_TIMER1_OVERFL);
  117. }
  118. int NutTraceInit(int size, char mode)
  119. {
  120. if (!trace_isinit) {
  121. // start timer1 at CPU frequency/8 and register interrupt service routine
  122. outb(TCCR1B, 2);
  123. NutRegisterIrqHandler(&sig_OVERFLOW1, NutTraceTimer1IRQ, 0);
  124. sbi(TIMSK, TOIE1);
  125. trace_isinit = 1;
  126. }
  127. if (size==0) {
  128. size = TRACE_SIZE_DEFAULT;
  129. }
  130. if (size != trace_size) {
  131. // current buffer is not of size that is wanted
  132. if (trace_items != 0) {
  133. // but memory is already allocated -> free old buffer
  134. NutHeapFree(trace_items);
  135. }
  136. // allocate buffer
  137. trace_items = (t_traceitem *)NutHeapAlloc(size * sizeof(t_traceitem));
  138. if (trace_items == 0) {
  139. // failed
  140. return trace_size = 0;
  141. }
  142. else {
  143. trace_size = size;
  144. }
  145. }
  146. // if (mode == TRACE_MODE_OFF) {
  147. // // if terminal-cmd "trace size <val>" is called trace is started in
  148. // // default mode
  149. // mode = TRACE_MODE_DEFAULT;
  150. // }
  151. trace_mode = mode;
  152. NutTraceClear();
  153. return trace_size;
  154. }
  155. void NutTraceClear()
  156. {
  157. trace_head = trace_isfull = 0;
  158. TRACE_ADD_ITEM(TRACE_TAG_START,0);
  159. }
  160. void NutTraceStop()
  161. {
  162. TRACE_ADD_ITEM(TRACE_TAG_STOP,0);
  163. trace_mode = TRACE_MODE_OFF;
  164. }
  165. void NutTraceTerminal(char* arg)
  166. {
  167. int val;
  168. if (sscanf(arg,"print%d",&val)==1) {
  169. NutTracePrint(val);
  170. return;
  171. }
  172. if (!strncmp(arg,"print",5)) {
  173. NutTracePrint(0);
  174. return;
  175. }
  176. if (!strncmp(arg,"oneshot",7)) {
  177. NutTraceInit(trace_size,TRACE_MODE_ONESHOT);
  178. printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
  179. return;
  180. }
  181. if (!strncmp(arg,"circular",8)) {
  182. NutTraceInit(trace_size,TRACE_MODE_CIRCULAR);
  183. printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
  184. return;
  185. }
  186. if (sscanf(arg,"size%d",&val)==1) {
  187. printf("TRACE new size: %d\n",NutTraceInit(val,trace_mode));
  188. return;
  189. }
  190. if (!strncmp(arg,"stop",4)) {
  191. NutTraceStop();
  192. printf("TRACE stopped\n");
  193. return;
  194. }
  195. if (sscanf(arg,"mask%d",&val)==1) {
  196. if (val<=TRACE_TAG_LAST) {
  197. trace_mask[val]=trace_mask[val] ? 0 : 1;
  198. NutTraceClear();
  199. }
  200. NutTraceMaskPrint();
  201. return;
  202. }
  203. if (!strncmp(arg,"mask",4)) {
  204. NutTraceMaskPrint();
  205. return;
  206. }
  207. NutTraceStatusPrint();
  208. printf("SYNTAX: trace [print [<size>]|oneshot|circular|size <size>|stop|mask [<tag>]]\n");
  209. }
  210. void NutTraceStatusPrint(void)
  211. {
  212. printf("TRACE STATUS\n");
  213. printf(" Mode is %s\n",mode_string[(int)trace_mode]);
  214. printf(" Size is %d\n",trace_size);
  215. if (trace_isfull)
  216. printf(" is full\n");
  217. else
  218. printf(" contains %d elements\n",trace_head);
  219. }
  220. void NutTracePrint(int size)
  221. {
  222. int i,index;
  223. uint32_t time;
  224. char mode;
  225. unsigned int micros, millis, secs;
  226. mode = trace_mode;
  227. trace_mode = TRACE_MODE_OFF;
  228. printf("\nTRACE");
  229. if (trace_size == 0) {
  230. printf(" not initialized!\n\n");
  231. return;
  232. }
  233. printf(" contains %d items, ",(trace_isfull ? trace_size : trace_head));
  234. if (size == 0) {
  235. size = trace_size;
  236. }
  237. if (trace_isfull) {
  238. if (size > trace_size) {
  239. size = trace_size;
  240. }
  241. }
  242. else {
  243. if (size > trace_head) {
  244. size = trace_head;
  245. }
  246. }
  247. printf(" printing %d items.\n",size);
  248. printf("%-20s%-12s%-12s\n","TAG","PC/Info","Time [s:ms:us]");
  249. printf("-----------------------------------------------\n");
  250. for (i=size-1;i>=0;i--) {
  251. index = trace_head - i - 1;
  252. if (index<0) {
  253. index += trace_size;
  254. }
  255. time = ((uint32_t)trace_items[index].time_h)<<16 | trace_items[index].time_l;
  256. micros = (int)(time%1000);
  257. millis = (int)((time/1000)%1000);
  258. secs = (int)(time/1000000);
  259. switch (trace_items[index].tag) {
  260. case TRACE_TAG_THREAD_YIELD:
  261. case TRACE_TAG_THREAD_SETPRIO:
  262. case TRACE_TAG_THREAD_WAIT:
  263. case TRACE_TAG_THREAD_SLEEP:
  264. printf("%-20s%-15s%7u:%03u:%03u\n",
  265. tag_string[(int)trace_items[index].tag],
  266. ((NUTTHREADINFO*)(trace_items[index].pc))->td_name,
  267. secs,millis,micros);
  268. break;
  269. case TRACE_TAG_INTERRUPT_ENTER:
  270. case TRACE_TAG_INTERRUPT_EXIT:
  271. printf("%-20s%-15s%7u:%03u:%03u\n",
  272. tag_string[(int)trace_items[index].tag],
  273. int_string[(int)trace_items[index].pc],
  274. secs,millis,micros);
  275. break;
  276. case TRACE_TAG_USER:
  277. printf("%-20s%-15s%7u:%03u:%03u\n",
  278. tag_string[(int)trace_items[index].tag],
  279. user_string[(int)trace_items[index].pc],
  280. secs,millis,micros);
  281. break;
  282. default:
  283. printf("%-20s%-#15x%7u:%03u:%03u\n",
  284. tag_string[(int)trace_items[index].tag],
  285. trace_items[index].pc,
  286. secs,millis,micros);
  287. }
  288. }
  289. trace_mode = mode;
  290. }
  291. int NutTraceGetPC(void)
  292. {
  293. int pc = ((int)(*((char*)SP+1)));
  294. pc = (pc<<8)|(0x00ff&(int)(*((char*)SP+2)));
  295. return pc<<1;
  296. }
  297. void NutTraceMaskSet(int tag)
  298. {
  299. if (tag<=TRACE_TAG_LAST) {
  300. trace_mask[tag] = 1;
  301. }
  302. }
  303. void NutTraceMaskClear(int tag)
  304. {
  305. if (tag<=TRACE_TAG_LAST) {
  306. trace_mask[tag] = 0;
  307. }
  308. }
  309. void NutTraceMaskPrint(void)
  310. {
  311. int tag;
  312. printf("TRACEMASK\n");
  313. for (tag=0;tag<=TRACE_TAG_LAST;tag++) {
  314. printf(" %d %s ",tag,tag_string[tag]);
  315. if (trace_mask[tag])
  316. printf("ON\n");
  317. else
  318. printf("OFF\n");
  319. }
  320. }
  321. int NutTraceRegisterUserTag(int tag, char* tag_string)
  322. {
  323. if (tag >= TRACE_MAX_USER)
  324. return -1;
  325. user_string[tag] = tag_string;
  326. return tag;
  327. }
  328. #endif