This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
gprof for the synthetic target
- From: Bart Veer <bartv at ecoscentric dot com>
- To: ecos-patches at ecos dot sourceware dot org
- Date: Mon, 21 Mar 2005 14:50:56 +0000 (GMT)
- Subject: gprof for the synthetic target
This adds profiling support (both mcount()/callgraph and a profiling
timer) to the synthetic target. Note that the results tend not to be
as useful as on a real target: at this level things like timers and
the idle thread don't work in quite the same way as on real h/w.
Enabling CYGIMP_HAL_IDLE_THREAD_SPIN will give somewhat better
results.
Bart
Index: hal/synth/i386linux/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/ChangeLog,v
retrieving revision 1.13
diff -u -r1.13 ChangeLog
--- hal/synth/i386linux/current/ChangeLog 11 Mar 2005 19:05:12 -0000 1.13
+++ hal/synth/i386linux/current/ChangeLog 21 Mar 2005 14:19:04 -0000
@@ -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:
Index: hal/synth/i386linux/current/cdl/hal_synth_i386.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/synth/i386linux/current/cdl/hal_synth_i386.cdl,v
retrieving revision 1.4
diff -u -r1.4 hal_synth_i386.cdl
--- hal/synth/i386linux/current/cdl/hal_synth_i386.cdl 22 Apr 2004 15:26:55 -0000 1.4
+++ hal/synth/i386linux/current/cdl/hal_synth_i386.cdl 21 Mar 2005 14:19:05 -0000
@@ -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 @@
# 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 @@
@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"
Index: hal/synth/i386linux/current/src/profile.c
===================================================================
RCS file: hal/synth/i386linux/current/src/profile.c
diff -N hal/synth/i386linux/current/src/profile.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ hal/synth/i386linux/current/src/profile.c 21 Mar 2005 14:19:05 -0000
@@ -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