tracer.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2000-2004 by ETH Zurich
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
00021  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.btnode.ethz.ch
00031  *
00032  */
00033  /*
00034  * os/tracer.c
00035  *
00036  * 22.12.2004 Philipp Blum <blum@tik.ee.ethz.ch>
00037  * 
00038  * \brief Routines to capture traces of nutOS programs
00039  * \note  Only supported on AVR-GCC platform
00040  * 
00041  */
00042 #if defined(__GNUC__) && defined(__AVR__)
00043  
00044 /************************************************/
00045 /* includes */
00046 /************************************************/
00047 #include <sys/tracer.h>            // t_traceitem, t_trace
00048 #include <sys/heap.h>              // NutHeapAlloc
00049 #include <sys/timer.h>             // NutGetMillis
00050 #include <sys/thread.h>            // NUTTHREADINFO
00051 #include <sys/atom.h>              // NutEnterCritical_notrace
00052 #include <dev/irqreg.h>            // sig_OVERFLOW1
00053 #include <stdio.h>                 // printf, sscanf
00054 #include <string.h>                // strcmp
00055 
00056 /************************************************/
00057 /* global variables */
00058 /************************************************/
00059 unsigned int micros_high           = 0;
00060 t_traceitem *trace_items    = 0;
00061 t_traceitem *trace_current  = 0;
00062 int trace_head              = 0;
00063 int trace_size              = 0;
00064 char trace_isfull           = 0;
00065 char trace_isinit           = 0;
00066 char trace_mode             = TRACE_MODE_OFF;
00067 
00068 char trace_mask[TRACE_TAG_LAST+1] = {
00069     0,
00070     0,
00071     1,
00072     1,
00073     1,
00074     1,
00075     0,
00076     0,
00077     1,
00078     1,
00079     1
00080 };
00081 
00082 char* tag_string[TRACE_TAG_LAST+1] = {
00083     "Critical  Enter",
00084     "Critical  Exit",
00085     "Thread    Yield",
00086     "Thread    SetPrio",
00087     "Thread    Wait",
00088     "Thread    Sleep",
00089     "Interrupt Enter",
00090     "Interrupt Exit",
00091     "Trace Start",
00092     "Trace Stop",
00093     "User *"
00094 };
00095 
00096 char* int_string[TRACE_INT_LAST+1] = {
00097     "UART0_CTS",
00098     "UART0_RXCOMPL",
00099     "UART0_TXEMPTY",
00100     "UART1_CTS",
00101     "UART1_RXCOMPL",
00102     "UART1_TXEMPTY",
00103     "TIMER0_OVERFL",
00104     "TIMER1_OVERFL",
00105     "SUART_TIMER",
00106     "SUART_RX"  
00107 };
00108 
00109 char* mode_string[TRACE_MODE_LAST+1] = {
00110     "OFF",
00111     "CIRCULAR",
00112     "ONESHOT"
00113 };
00114 
00115 char* user_string[TRACE_MAX_USER];
00116     
00117 /************************************************/
00118 /* function definitions */
00119 /************************************************/
00120 static void NutTraceTimer1IRQ(void *arg)
00121 {
00122 //  TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_ENTER,TRACE_INT_TIMER1_OVERFL);
00123     micros_high++;
00124 //  TRACE_ADD_ITEM(TRACE_TAG_INTERRUPT_EXIT,TRACE_INT_TIMER1_OVERFL);
00125 }
00126 
00127 
00128 
00129 int NutTraceInit(int size, char mode) 
00130 {
00131     if (!trace_isinit) {
00132         // start timer1 at CPU frequency/8 and register interrupt service routine
00133         outb(TCCR1B, 2);
00134         NutRegisterIrqHandler(&sig_OVERFLOW1, NutTraceTimer1IRQ, 0);
00135         sbi(TIMSK, TOIE1);
00136         trace_isinit = 1;
00137     }       
00138     if (size==0) {
00139         size = TRACE_SIZE_DEFAULT;
00140     }   
00141     if (size != trace_size) {
00142         // current buffer is not of size that is wanted
00143         if (trace_items != 0) {
00144             // but memory is already allocated -> free old buffer
00145             NutHeapFree(trace_items);
00146         }
00147         // allocate buffer
00148         trace_items = (t_traceitem *)NutHeapAlloc(size * sizeof(t_traceitem));
00149         if (trace_items == 0) {
00150             // failed
00151             return trace_size = 0;
00152         }
00153         else {
00154             trace_size = size;
00155         }
00156     }
00157 
00158 //  if (mode == TRACE_MODE_OFF) {
00159 //      // if terminal-cmd "trace size <val>" is called trace is started in
00160 //      // default mode
00161 //      mode = TRACE_MODE_DEFAULT;
00162 //  }
00163     trace_mode   = mode;
00164     NutTraceClear();    
00165     return trace_size;      
00166 }
00167 
00168 
00169 
00170 void NutTraceClear()
00171 {
00172     trace_head = trace_isfull = 0;
00173     TRACE_ADD_ITEM(TRACE_TAG_START,0);
00174 }
00175 
00176 void NutTraceStop()
00177 {
00178     TRACE_ADD_ITEM(TRACE_TAG_STOP,0);
00179     trace_mode = TRACE_MODE_OFF;
00180 }
00181 
00182 void NutTraceTerminal(char* arg)
00183 {
00184     int val;
00185 
00186     if (sscanf(arg,"print%d",&val)==1) {
00187         NutTracePrint(val);
00188         return;
00189     }
00190     if (!strncmp(arg,"print",5)) {
00191         NutTracePrint(0);
00192         return;
00193     }
00194     if (!strncmp(arg,"oneshot",7)) {
00195         NutTraceInit(trace_size,TRACE_MODE_ONESHOT);
00196         printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
00197         return;
00198     }
00199     if (!strncmp(arg,"circular",8)) {
00200         NutTraceInit(trace_size,TRACE_MODE_CIRCULAR);
00201         printf("TRACE mode %s, restarted\n",mode_string[(int)trace_mode]);
00202         return;
00203     }
00204     if (sscanf(arg,"size%d",&val)==1) {
00205         printf("TRACE new size: %d\n",NutTraceInit(val,trace_mode));
00206         return;
00207     }
00208     if (!strncmp(arg,"stop",4)) {
00209         NutTraceStop();
00210         printf("TRACE stopped\n");
00211         return;
00212     }
00213     if (sscanf(arg,"mask%d",&val)==1) {
00214         if (val<=TRACE_TAG_LAST) {
00215             trace_mask[val]=trace_mask[val] ? 0 : 1;
00216             NutTraceClear();
00217         }
00218         NutTraceMaskPrint();
00219         return;
00220     }
00221     if (!strncmp(arg,"mask",4)) {
00222         NutTraceMaskPrint();
00223         return;
00224     }
00225 
00226     
00227     NutTraceStatusPrint();
00228     printf("SYNTAX: trace [print [<size>]|oneshot|circular|size <size>|stop|mask [<tag>]]\n");
00229 }
00230 
00231 void NutTraceStatusPrint(void)
00232 {
00233     printf("TRACE STATUS\n");
00234     printf(" Mode is %s\n",mode_string[(int)trace_mode]);
00235     printf(" Size is %d\n",trace_size);
00236     if (trace_isfull)
00237         printf(" is full\n");
00238     else
00239         printf(" contains %d elements\n",trace_head);       
00240 }
00241 
00242 void NutTracePrint(int size)
00243 {
00244     int i,index;
00245     uint32_t time;
00246     char mode;
00247     unsigned int micros, millis, secs;
00248 
00249     mode = trace_mode;
00250     trace_mode = TRACE_MODE_OFF;
00251     printf("\nTRACE");
00252     if (trace_size == 0) {
00253         printf(" not initialized!\n\n");
00254         return;
00255     }
00256     printf(" contains %d items, ",(trace_isfull ? trace_size : trace_head));
00257     if (size == 0) {
00258         size = trace_size;
00259     }
00260     if (trace_isfull) {
00261         if (size > trace_size) {
00262             size = trace_size;
00263         }
00264     }   
00265     else {
00266         if (size > trace_head) {
00267             size = trace_head;
00268         }
00269     }
00270     printf(" printing %d items.\n",size);
00271     printf("%-20s%-12s%-12s\n","TAG","PC/Info","Time [s:ms:us]");
00272     printf("-----------------------------------------------\n");
00273     for (i=size-1;i>=0;i--) {
00274         index = trace_head - i - 1;
00275         if (index<0) {
00276             index += trace_size;
00277         }
00278         time = ((uint32_t)trace_items[index].time_h)<<16 | trace_items[index].time_l;
00279         micros = (int)(time%1000);
00280         millis = (int)((time/1000)%1000);
00281         secs   = (int)(time/1000000);
00282         switch (trace_items[index].tag) {
00283             case TRACE_TAG_THREAD_YIELD:
00284             case TRACE_TAG_THREAD_SETPRIO:
00285             case TRACE_TAG_THREAD_WAIT:
00286             case TRACE_TAG_THREAD_SLEEP:
00287                 printf("%-20s%-15s%7u:%03u:%03u\n",
00288                         tag_string[(int)trace_items[index].tag],
00289                         ((NUTTHREADINFO*)(trace_items[index].pc))->td_name,
00290                         secs,millis,micros);
00291                 break;
00292             case TRACE_TAG_INTERRUPT_ENTER:
00293             case TRACE_TAG_INTERRUPT_EXIT:
00294                 printf("%-20s%-15s%7u:%03u:%03u\n",
00295                         tag_string[(int)trace_items[index].tag],
00296                         int_string[(int)trace_items[index].pc],
00297                         secs,millis,micros);
00298                 break;
00299             case TRACE_TAG_USER:
00300                 printf("%-20s%-15s%7u:%03u:%03u\n",
00301                         tag_string[(int)trace_items[index].tag],
00302                         user_string[(int)trace_items[index].pc],
00303                         secs,millis,micros);
00304                 break;
00305             default:
00306                 printf("%-20s%-#15x%7u:%03u:%03u\n",
00307                         tag_string[(int)trace_items[index].tag],
00308                         trace_items[index].pc,
00309                         secs,millis,micros);
00310         }
00311     }
00312     trace_mode = mode;
00313 }
00314 
00315 int NutTraceGetPC(void)
00316 {
00317     int pc = ((int)(*((char*)SP+1)));
00318     pc = (pc<<8)|(0x00ff&(int)(*((char*)SP+2)));
00319     return pc<<1;
00320 } 
00321 
00322 
00323 void NutTraceMaskSet(int tag)
00324 {
00325     if (tag<=TRACE_TAG_LAST) {
00326         trace_mask[tag] = 1;
00327     }
00328 }
00329 
00330 void NutTraceMaskClear(int tag)
00331 {
00332     if (tag<=TRACE_TAG_LAST) {
00333         trace_mask[tag] = 0;
00334     }
00335 }
00336 
00337 void NutTraceMaskPrint(void)
00338 {
00339     int tag;
00340     printf("TRACEMASK\n");
00341     for (tag=0;tag<=TRACE_TAG_LAST;tag++) {
00342         printf(" %d %s ",tag,tag_string[tag]);
00343         if (trace_mask[tag])
00344             printf("ON\n");
00345         else
00346             printf("OFF\n");
00347     }                   
00348 }
00349 
00350 int NutTraceRegisterUserTag(int tag, char* tag_string)
00351 {
00352     if (tag >= TRACE_MAX_USER)
00353         return -1;
00354 
00355     user_string[tag] = tag_string;
00356     return tag;     
00357 }
00358 #endif

© 2000-2010 by contributors - visit http://www.ethernut.de/