]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/synth/i386linux/v2_0/src/profile.c
Initial revision
[karo-tx-redboot.git] / packages / hal / synth / i386linux / v2_0 / src / profile.c
1 //=============================================================================
2 //
3 //      profile.c
4 //
5 //      Support for profiling on x86 synthetic target
6 //
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003, 2005 eCosCentric Ltd
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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####
39 //
40 // Author(s):    bartv
41 // Contributors: bartv
42 // Date:         2003-10-12
43 //
44 //####DESCRIPTIONEND####
45 //=============================================================================
46
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>
56
57 #if 1
58 // Profiling support.
59 //
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.
65 //
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.
69 static void
70 synth_prof_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
71 {
72     __profile_hit((CYG_ADDRWORD) context.hal_eip);
73     CYG_UNUSED_PARAM(int, sig);
74 }
75
76 int
77 hal_enable_profile_timer(int resolution)
78 {
79     struct cyg_hal_sys_sigaction    action;
80     struct cyg_hal_sys_sigset_t     mask;
81     struct cyg_hal_sys_itimerval    timer;
82
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;
92     
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");
95     }
96
97     // The resolution is limited by the underlying 100Hz system clock,
98     // there is no hardware timer which can generate faster clock
99     // interrupts.
100     if (resolution < 10000) {
101         resolution = 10000;
102     } else {
103         resolution  = (resolution + 5000) / 10000;
104         resolution *= 10000;
105     }
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");
112     }
113
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");
119     }
120
121     return resolution;
122 }
123
124 #else
125
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);
129
130 static void
131 synth_profile_alrm_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
132 {
133     __profile_hit((CYG_ADDRWORD) context.hal_eip);
134     (*synth_profile_old_alrm_sighandler)(sig);
135 }
136
137 int
138 hal_enable_profile_timer(int resolution)
139 {
140     struct cyg_hal_sys_sigaction    action;
141
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");
144     }
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");
149     }
150
151     return CYGNUM_HAL_RTC_PERIOD;
152 }
153
154 #endif
155
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.
166 void
167 mcount(void)
168 {
169     static int  nested = 0;
170     int         enabled;
171
172     HAL_DISABLE_INTERRUPTS(enabled);
173     if (!nested) {
174         nested = 1;
175         __profile_mcount((CYG_ADDRWORD)__builtin_return_address(1),
176                          (CYG_ADDRWORD)__builtin_return_address(0));
177         nested = 0;
178     }
179     HAL_RESTORE_INTERRUPTS(enabled);
180 }
181
182 #endif