From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrew Lunn To: "Natarajan, Mekala (CTS)" Cc: "'ecos-discuss@sources.redhat.com'" Subject: Re: [ECOS] profiling Date: Thu, 22 Feb 2001 02:59:00 -0000 Message-id: <20010222115919.L15944@biferten.ma.tech.ascom.ch> References: <8F1D166D08ACD41196EE00B0D020944B68B6F3@CTSINENTSXUB> X-SW-Source: 2001-02/msg00355.html 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 #include #include #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