This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: profiling


On Thu, Feb 22, 2001 at 04:07:25PM +0530, Natarajan, Mekala (CTS) wrote:
> Hi all,
> 	Can someone suggest the profiling & analysis tools  available for
> ECOS.
> Thanks,
> mekala

I wrote a quick and dirty profiler. It directly uses the hardware
timers on the EBSA SA110 board so you will have to do some work to
port it to other platforms. It uses the same scheme as the Linux
kernel profiler. It builds up a profile table in the same way and its
compatible with the readprofile program. The hard bit is getting the
table off the target hardware and onto a Linux box where is can be
processed. You have to use some sort of network.

        Andrew

/* A quick and dirty profiler. Andrew.Lunn@ascom.ch */

#include <cyg/kernel/kapi.h>
#include <cyg/hal/hal_ebsa285.h>
#include <cyg/hal/hal_arch.h>
#include "cfg.h"
#include "dbgprint.h"
#include "assert.h"
#include "profiler.h"

/* This is the table we store the date in. Each entry tells you have
   often the CPU has in the range of addresses PROF_RESOLUTION bits
   wide when the timer went off.*/
volatile cyg_uint32 prof_table [PROF_TABLE_SIZE]; 

static volatile cyg_uint32 prof_table_misses;  /* How many times did we miss
                                                  the table */
static volatile cyg_uint32 prof_ticks;         /* How many ticks the profiler
                                                  has received */

static cyg_interrupt intr;            /* eCos control structure */
static cyg_handle_t  intr_handle;    
static profile_states_t prof_state = PROF_UNINIT;

/* Reset the profile table back into a clean state. Also sets the
   number of misses to zero */
void
prof_table_clear(void)
{
  memset((void *)prof_table,0,sizeof(prof_table));
  prof_table_misses = 0;
  prof_ticks = 0;

  /* The Linux profiler tool wants the first word to contain the resoluton. */
  prof_table[0] = 1 << PROF_RESOLUTION;
}

/* Give an address increment the count in the profile table. If the
   address misses the table incremenet the miss count */
static void __inline__ 
prof_table_increment(cyg_addrword_t addr)
{
  prof_ticks++;

  if ( (addr < PROF_MEMORY_BOTTOM) || 
       (addr > PROF_MEMORY_TOP)) {
    prof_table_misses++;
  } else {
    addr -= PROF_MEMORY_BOTTOM;
    addr = addr >> PROF_RESOLUTION;
    
    if (prof_table[addr] != 0xffffffff) {
      prof_table[addr]++;
    }
  }
}

/* Start the timer used by the profiler code. This uses TIMER2 on the
   EBSA. */
static void 
prof_start_timer(void) {

  *SA110_TIMER2_CONTROL = 0; /* Disable while playing with it */
  *SA110_TIMER2_LOAD = TIMER2_FREQ / PROF_FREQ;
  *SA110_TIMER2_CLEAR = 0; /* Clear any pending interrupts */
  *SA110_TIMER2_CONTROL = (SA110_TIMER_CONTROL_SCALE_1 |
                           SA110_TIMER_CONTROL_MODE |
                           SA110_TIMER_CONTROL_ENABLE );
  *SA110_TIMER2_CLEAR = 0; /* Clear any pending interrupts again */
}

/* Stop the timer used by the profiler. */
static void
prof_stop_timer(void) {

  *SA110_TIMER2_CONTROL = 0;
}

/* Clear timer interrupt */
static void __inline__
prof_clear_timer_intr(void) {
  *SA110_TIMER2_CLEAR = 0;
}

/* This is the interrupt handler. It finds out the PC address before
   the interrupt and calls the increment. It then clears the interrupt
   and returns */
static cyg_uint32 
prof_ISR(cyg_vector_t vector, cyg_addrword_t data,HAL_SavedRegisters *regs) {

  prof_table_increment(regs->pc-4); /* Current instruction, not next */
  
  prof_clear_timer_intr();
  
  cyg_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_TIMER_2);
  
  return (CYG_ISR_HANDLED);
}

/* Install the interrupt handler for the timer used by the profiler */
static void 
prof_install_ISR (void) {
  
  cyg_interrupt_create(CYGNUM_HAL_INTERRUPT_TIMER_2,
                       0,
                       0,
                       prof_ISR,
                       NULL,
                       &intr_handle,
                       &intr);

  cyg_interrupt_attach(intr_handle);
  cyg_interrupt_unmask(CYGNUM_HAL_INTERRUPT_TIMER_2);
}

/* This function initialises the profiler */
void 
prof_init(void) {
  prof_table_clear();
  prof_install_ISR();
  prof_state = PROF_INIT;
}

/* This function starts the profiler running. */
void
prof_start(void) {
  prof_start_timer();
  prof_state = PROF_START;
}

/* Stop the profiler. Its a good idea to do this before you
   read the data from the table or you also profile the reading 
   process */
void 
prof_stop(void) {
  prof_stop_timer();
  prof_state = PROF_STOP;
}

/* Interface to the profiler code */

#ifndef PROFILER_H
#define PROFILER_H
typedef enum {PROF_UNINIT = 0, PROF_INIT, PROF_START, PROF_STOP} profile_states_t;

/* Reset the profile table back into a clean state. Also sets the
   number of misses to zero */
void prof_table_clear(void);

/* This function initialises the profiler and sets its running */
void prof_init(void);

/* Stop the profiler. Its a good idea to do this before you
   read the data from the table or you also profile the reading 
   process */
void prof_stop(void);

#define PROF_MEMORY_BOTTOM 0x00000000
#define PROF_MEMORY_TOP    0x000F0000
#define PROF_MEMORY_SIZE   (PROF_MEMORY_TOP - PROF_MEMORY_BOTTOM)
#define PROF_RESOLUTION    2   /* This is the number of bits we discard from
                                  from the bottom of the address. */
#define PROF_TABLE_SIZE    (PROF_MEMORY_SIZE >> PROF_RESOLUTION)
#define PROF_FREQ          1111     /* How many times a second */
#define TIMER2_FREQ        50000000 /* The clock frequency of timer 2 */

extern volatile cyg_uint32 prof_table [PROF_TABLE_SIZE];
#endif





Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]