Mercurial > ecos-v3_0-branch
changeset 1915:0fd6e58dc450
Add profiling support to the synthetic target
| author | bartv |
|---|---|
| date | Mon, 21 Mar 2005 14:37:02 +0000 |
| parents | d485b9fe6131 |
| children | 5089baca98c7 |
| files | packages/hal/synth/i386linux/current/ChangeLog packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl packages/hal/synth/i386linux/current/src/profile.c |
| diffstat | 3 files changed, 191 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/hal/synth/i386linux/current/ChangeLog +++ b/packages/hal/synth/i386linux/current/ChangeLog @@ -1,3 +1,7 @@ +2005-03-21 Bart Veer <bartv@ecoscentric.com> + + * cdl/hal_synth_i386.cdl, src/profile.c: add profiling support. + 2005-03-11 Bart Veer <bartv@ecoscentric.com> * include/var_io.h, src/syscall-i386-linux-1.0.S:
--- a/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl +++ b/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl @@ -8,6 +8,7 @@ #####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. +## Copyright (C) 2005 eCosCentric Ltd ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. ## ## eCos is free software; you can redistribute it and/or modify it under @@ -66,6 +67,9 @@ cdl_package CYGPKG_HAL_SYNTH_I386 { # the recommended minimum from var_arch.h requires { !CYGPKG_LIBC_STARTUP || CYGINT_LIBC_STARTUP_MAIN_NO_STACK_SIZE || (CYGNUM_LIBC_MAIN_DEFAULT_STACK_SIZE >= (16 * 1024)) } + implements CYGINT_PROFILE_HAL_TIMER + implements CYGINT_PROFILE_HAL_MCOUNT + make { <PREFIX>/lib/vectors.o : <PACKAGE>/src/vectors.S $(CC) -Wp,-MD,vectors.tmp $(INCLUDE_PATH) $(CFLAGS) -c -o $@ $< @@ -74,7 +78,7 @@ cdl_package CYGPKG_HAL_SYNTH_I386 { @echo >> $(notdir $@).deps @rm vectors.tmp } - compile context.S syscall-i386-linux-1.0.S + compile context.S syscall-i386-linux-1.0.S profile.c cdl_component CYG_HAL_STARTUP { display "Startup type"
new file mode 100644 --- /dev/null +++ b/packages/hal/synth/i386linux/current/src/profile.c @@ -0,0 +1,182 @@ +//============================================================================= +// +// profile.c +// +// Support for profiling on x86 synthetic target +// +//============================================================================= +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003, 2005 eCosCentric Ltd +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): bartv +// Contributors: bartv +// Date: 2003-10-12 +// +//####DESCRIPTIONEND#### +//============================================================================= + +#include <pkgconf/system.h> +#ifdef CYGPKG_PROFILE_GPROF +#include <pkgconf/hal_synth.h> +#include <pkgconf/hal_synth_i386.h> +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/hal/hal_io.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/profile/profile.h> + +#if 1 +// Profiling support. +// +// The profile timer uses the ITIMER_PROF, which means we get a SIGPROF +// signal at the desired rate. The signal handler can obtain the address +// of the interrupted code via a sigcontext structure. The contents of +// the sigcontext structure and exactly how it gets passed to the signal +// handler depends on the architecture, hence this code is x86-specific. +// +// The results of this profiling code seem a lot poorer than on other +// targets, but it is not clear why. There may be some subtle +// interaction between the system and profiling clocks. +static void +synth_prof_sighandler(int sig, struct cyg_hal_sys_sigcontext context) +{ + __profile_hit((CYG_ADDRWORD) context.hal_eip); + CYG_UNUSED_PARAM(int, sig); +} + +int +hal_enable_profile_timer(int resolution) +{ + struct cyg_hal_sys_sigaction action; + struct cyg_hal_sys_sigset_t mask; + struct cyg_hal_sys_itimerval timer; + + // We want profiling to be an atomic operation. __profile_hit() is + // a very simple function which should return quickly, and there + // is no need for a DSR or context switching. Hence everything + // including SIGIO and SIGALRM are blocked, effectively giving the + // profiling timer the highest priority. + action.hal_mask = 0xffffffff; + action.hal_flags = CYG_HAL_SYS_SA_RESTORER; + action.hal_handler = (void (*)(int)) &synth_prof_sighandler; + action.hal_restorer = &cyg_hal_sys_restore; + + if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGPROF, &action, (struct cyg_hal_sys_sigaction*) 0)) { + CYG_FAIL("Failed to install signal handler for SIGPROF"); + } + + // The resolution is limited by the underlying 100Hz system clock, + // there is no hardware timer which can generate faster clock + // interrupts. + if (resolution < 10000) { + resolution = 10000; + } else { + resolution = (resolution + 5000) / 10000; + resolution *= 10000; + } + timer.hal_it_interval.hal_tv_sec = 0; + timer.hal_it_interval.hal_tv_usec = resolution; + timer.hal_it_value.hal_tv_sec = 0; + timer.hal_it_value.hal_tv_usec = resolution; + if (0 != cyg_hal_sys_setitimer(CYG_HAL_SYS_ITIMER_PROF, &timer, (struct cyg_hal_sys_itimerval*) 0)) { + CYG_FAIL("Failed to initialize the profiling itimer"); + } + + // Now unblock SIGPROF + CYG_HAL_SYS_SIGEMPTYSET(&mask); + CYG_HAL_SYS_SIGADDSET(&mask, CYG_HAL_SYS_SIGPROF); + if (0 != cyg_hal_sys_sigprocmask(CYG_HAL_SYS_SIG_UNBLOCK, &mask, (cyg_hal_sys_sigset_t*)0)) { + CYG_FAIL("Failed to unblock SIGPROF"); + } + + return resolution; +} + +#else + +// An alternative implementation that overloads the SIGALRM handler +// rather than using SIGPROF. It does not seem to work any better. +static void (*synth_profile_old_alrm_sighandler)(int); + +static void +synth_profile_alrm_sighandler(int sig, struct cyg_hal_sys_sigcontext context) +{ + __profile_hit((CYG_ADDRWORD) context.hal_eip); + (*synth_profile_old_alrm_sighandler)(sig); +} + +int +hal_enable_profile_timer(int resolution) +{ + struct cyg_hal_sys_sigaction action; + + if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, (const struct cyg_hal_sys_sigaction*)0, &action)) { + CYG_FAIL("Failed to retrieve old signal handler for SIGALRM"); + } + synth_profile_old_alrm_sighandler = action.hal_handler; + action.hal_handler = (void (*)(int)) &synth_profile_alrm_sighandler; + if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, &action, (struct cyg_hal_sys_sigaction*)0)) { + CYG_FAIL("Failed to install new signal handler for SIGALRM"); + } + + return CYGNUM_HAL_RTC_PERIOD; +} + +#endif + +// mcount() can be implemented largely using compiler built-ins. However +// there are two complications. The generic profiling code assumes +// __profile_mcount() is called with interrupts disabled. Blocking interrupts +// won't stop the low-level signal handlers, so mcount() calls from those +// may get lost because of the nesting test but that is fairly harmless. +// Those signal handlers will complete before control returns here, i.e. +// we have strict nesting, so there is no risk of the nested flag remaining +// set while a context switch occurs. Also if eCos itself is built with +// -pg then the compiler will insert a recursive call to mcount(), and +// we have to guard against that. +void +mcount(void) +{ + static int nested = 0; + int enabled; + + HAL_DISABLE_INTERRUPTS(enabled); + if (!nested) { + nested = 1; + __profile_mcount((CYG_ADDRWORD)__builtin_return_address(1), + (CYG_ADDRWORD)__builtin_return_address(0)); + nested = 0; + } + HAL_RESTORE_INTERRUPTS(enabled); +} + +#endif
