1 //=============================================================================
5 // Support for profiling on x86 synthetic target
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003, 2005 eCosCentric Ltd
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //=============================================================================
38 //#####DESCRIPTIONBEGIN####
41 // Contributors: bartv
44 //####DESCRIPTIONEND####
45 //=============================================================================
47 #include <pkgconf/system.h>
48 #ifdef CYGPKG_PROFILE_GPROF
49 #include <pkgconf/hal_synth.h>
50 #include <pkgconf/hal_synth_i386.h>
51 #include <cyg/infra/cyg_type.h>
52 #include <cyg/infra/cyg_ass.h>
53 #include <cyg/hal/hal_io.h>
54 #include <cyg/hal/hal_intr.h>
55 #include <cyg/profile/profile.h>
60 // The profile timer uses the ITIMER_PROF, which means we get a SIGPROF
61 // signal at the desired rate. The signal handler can obtain the address
62 // of the interrupted code via a sigcontext structure. The contents of
63 // the sigcontext structure and exactly how it gets passed to the signal
64 // handler depends on the architecture, hence this code is x86-specific.
66 // The results of this profiling code seem a lot poorer than on other
67 // targets, but it is not clear why. There may be some subtle
68 // interaction between the system and profiling clocks.
70 synth_prof_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
72 __profile_hit((CYG_ADDRWORD) context.hal_eip);
73 CYG_UNUSED_PARAM(int, sig);
77 hal_enable_profile_timer(int resolution)
79 struct cyg_hal_sys_sigaction action;
80 struct cyg_hal_sys_sigset_t mask;
81 struct cyg_hal_sys_itimerval timer;
83 // We want profiling to be an atomic operation. __profile_hit() is
84 // a very simple function which should return quickly, and there
85 // is no need for a DSR or context switching. Hence everything
86 // including SIGIO and SIGALRM are blocked, effectively giving the
87 // profiling timer the highest priority.
88 action.hal_mask = 0xffffffff;
89 action.hal_flags = CYG_HAL_SYS_SA_RESTORER;
90 action.hal_handler = (void (*)(int)) &synth_prof_sighandler;
91 action.hal_restorer = &cyg_hal_sys_restore;
93 if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGPROF, &action, (struct cyg_hal_sys_sigaction*) 0)) {
94 CYG_FAIL("Failed to install signal handler for SIGPROF");
97 // The resolution is limited by the underlying 100Hz system clock,
98 // there is no hardware timer which can generate faster clock
100 if (resolution < 10000) {
103 resolution = (resolution + 5000) / 10000;
106 timer.hal_it_interval.hal_tv_sec = 0;
107 timer.hal_it_interval.hal_tv_usec = resolution;
108 timer.hal_it_value.hal_tv_sec = 0;
109 timer.hal_it_value.hal_tv_usec = resolution;
110 if (0 != cyg_hal_sys_setitimer(CYG_HAL_SYS_ITIMER_PROF, &timer, (struct cyg_hal_sys_itimerval*) 0)) {
111 CYG_FAIL("Failed to initialize the profiling itimer");
114 // Now unblock SIGPROF
115 CYG_HAL_SYS_SIGEMPTYSET(&mask);
116 CYG_HAL_SYS_SIGADDSET(&mask, CYG_HAL_SYS_SIGPROF);
117 if (0 != cyg_hal_sys_sigprocmask(CYG_HAL_SYS_SIG_UNBLOCK, &mask, (cyg_hal_sys_sigset_t*)0)) {
118 CYG_FAIL("Failed to unblock SIGPROF");
126 // An alternative implementation that overloads the SIGALRM handler
127 // rather than using SIGPROF. It does not seem to work any better.
128 static void (*synth_profile_old_alrm_sighandler)(int);
131 synth_profile_alrm_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
133 __profile_hit((CYG_ADDRWORD) context.hal_eip);
134 (*synth_profile_old_alrm_sighandler)(sig);
138 hal_enable_profile_timer(int resolution)
140 struct cyg_hal_sys_sigaction action;
142 if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, (const struct cyg_hal_sys_sigaction*)0, &action)) {
143 CYG_FAIL("Failed to retrieve old signal handler for SIGALRM");
145 synth_profile_old_alrm_sighandler = action.hal_handler;
146 action.hal_handler = (void (*)(int)) &synth_profile_alrm_sighandler;
147 if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, &action, (struct cyg_hal_sys_sigaction*)0)) {
148 CYG_FAIL("Failed to install new signal handler for SIGALRM");
151 return CYGNUM_HAL_RTC_PERIOD;
156 // mcount() can be implemented largely using compiler built-ins. However
157 // there are two complications. The generic profiling code assumes
158 // __profile_mcount() is called with interrupts disabled. Blocking interrupts
159 // won't stop the low-level signal handlers, so mcount() calls from those
160 // may get lost because of the nesting test but that is fairly harmless.
161 // Those signal handlers will complete before control returns here, i.e.
162 // we have strict nesting, so there is no risk of the nested flag remaining
163 // set while a context switch occurs. Also if eCos itself is built with
164 // -pg then the compiler will insert a recursive call to mcount(), and
165 // we have to guard against that.
169 static int nested = 0;
172 HAL_DISABLE_INTERRUPTS(enabled);
175 __profile_mcount((CYG_ADDRWORD)__builtin_return_address(1),
176 (CYG_ADDRWORD)__builtin_return_address(0));
179 HAL_RESTORE_INTERRUPTS(enabled);