1 |
786 |
skrzyp |
//=============================================================================
|
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 Free Software Foundation, Inc.
|
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
|
16 |
|
|
// version.
|
17 |
|
|
//
|
18 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
19 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
20 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
21 |
|
|
// for more details.
|
22 |
|
|
//
|
23 |
|
|
// You should have received a copy of the GNU General Public License
|
24 |
|
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
25 |
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
|
|
//
|
27 |
|
|
// As a special exception, if other files instantiate templates or use
|
28 |
|
|
// macros or inline functions from this file, or you compile this file
|
29 |
|
|
// and link it with other works to produce a work based on this file,
|
30 |
|
|
// this file does not by itself cause the resulting work to be covered by
|
31 |
|
|
// the GNU General Public License. However the source code for this file
|
32 |
|
|
// must still be made available in accordance with section (3) of the GNU
|
33 |
|
|
// General Public License v2.
|
34 |
|
|
//
|
35 |
|
|
// This exception does not invalidate any other reasons why a work based
|
36 |
|
|
// on this file might be covered by the GNU General Public License.
|
37 |
|
|
// -------------------------------------------
|
38 |
|
|
// ####ECOSGPLCOPYRIGHTEND####
|
39 |
|
|
//=============================================================================
|
40 |
|
|
//#####DESCRIPTIONBEGIN####
|
41 |
|
|
//
|
42 |
|
|
// Author(s): bartv
|
43 |
|
|
// Contributors: bartv
|
44 |
|
|
// Date: 2003-10-12
|
45 |
|
|
//
|
46 |
|
|
//####DESCRIPTIONEND####
|
47 |
|
|
//=============================================================================
|
48 |
|
|
|
49 |
|
|
#include <pkgconf/system.h>
|
50 |
|
|
#ifdef CYGPKG_PROFILE_GPROF
|
51 |
|
|
#include <pkgconf/hal_synth.h>
|
52 |
|
|
#include <pkgconf/hal_synth_i386.h>
|
53 |
|
|
#include <cyg/infra/cyg_type.h>
|
54 |
|
|
#include <cyg/infra/cyg_ass.h>
|
55 |
|
|
#include <cyg/hal/hal_io.h>
|
56 |
|
|
#include <cyg/hal/hal_intr.h>
|
57 |
|
|
#include <cyg/profile/profile.h>
|
58 |
|
|
|
59 |
|
|
#if 1
|
60 |
|
|
// Profiling support.
|
61 |
|
|
//
|
62 |
|
|
// The profile timer uses the ITIMER_PROF, which means we get a SIGPROF
|
63 |
|
|
// signal at the desired rate. The signal handler can obtain the address
|
64 |
|
|
// of the interrupted code via a sigcontext structure. The contents of
|
65 |
|
|
// the sigcontext structure and exactly how it gets passed to the signal
|
66 |
|
|
// handler depends on the architecture, hence this code is x86-specific.
|
67 |
|
|
//
|
68 |
|
|
// The results of this profiling code seem a lot poorer than on other
|
69 |
|
|
// targets, but it is not clear why. There may be some subtle
|
70 |
|
|
// interaction between the system and profiling clocks.
|
71 |
|
|
static void
|
72 |
|
|
synth_prof_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
|
73 |
|
|
{
|
74 |
|
|
__profile_hit((CYG_ADDRWORD) context.hal_eip);
|
75 |
|
|
CYG_UNUSED_PARAM(int, sig);
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
int
|
79 |
|
|
hal_enable_profile_timer(int resolution)
|
80 |
|
|
{
|
81 |
|
|
struct cyg_hal_sys_sigaction action;
|
82 |
|
|
struct cyg_hal_sys_sigset_t mask;
|
83 |
|
|
struct cyg_hal_sys_itimerval timer;
|
84 |
|
|
|
85 |
|
|
// We want profiling to be an atomic operation. __profile_hit() is
|
86 |
|
|
// a very simple function which should return quickly, and there
|
87 |
|
|
// is no need for a DSR or context switching. Hence everything
|
88 |
|
|
// including SIGIO and SIGALRM are blocked, effectively giving the
|
89 |
|
|
// profiling timer the highest priority.
|
90 |
|
|
action.hal_mask = 0xffffffff;
|
91 |
|
|
action.hal_flags = CYG_HAL_SYS_SA_RESTORER;
|
92 |
|
|
action.hal_handler = (void (*)(int)) &synth_prof_sighandler;
|
93 |
|
|
action.hal_restorer = &cyg_hal_sys_restore;
|
94 |
|
|
|
95 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGPROF, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
96 |
|
|
CYG_FAIL("Failed to install signal handler for SIGPROF");
|
97 |
|
|
}
|
98 |
|
|
|
99 |
|
|
// The resolution is limited by the underlying 100Hz system clock,
|
100 |
|
|
// there is no hardware timer which can generate faster clock
|
101 |
|
|
// interrupts.
|
102 |
|
|
if (resolution < 10000) {
|
103 |
|
|
resolution = 10000;
|
104 |
|
|
} else {
|
105 |
|
|
resolution = (resolution + 5000) / 10000;
|
106 |
|
|
resolution *= 10000;
|
107 |
|
|
}
|
108 |
|
|
timer.hal_it_interval.hal_tv_sec = 0;
|
109 |
|
|
timer.hal_it_interval.hal_tv_usec = resolution;
|
110 |
|
|
timer.hal_it_value.hal_tv_sec = 0;
|
111 |
|
|
timer.hal_it_value.hal_tv_usec = resolution;
|
112 |
|
|
if (0 != cyg_hal_sys_setitimer(CYG_HAL_SYS_ITIMER_PROF, &timer, (struct cyg_hal_sys_itimerval*) 0)) {
|
113 |
|
|
CYG_FAIL("Failed to initialize the profiling itimer");
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
// Now unblock SIGPROF
|
117 |
|
|
CYG_HAL_SYS_SIGEMPTYSET(&mask);
|
118 |
|
|
CYG_HAL_SYS_SIGADDSET(&mask, CYG_HAL_SYS_SIGPROF);
|
119 |
|
|
if (0 != cyg_hal_sys_sigprocmask(CYG_HAL_SYS_SIG_UNBLOCK, &mask, (cyg_hal_sys_sigset_t*)0)) {
|
120 |
|
|
CYG_FAIL("Failed to unblock SIGPROF");
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
return resolution;
|
124 |
|
|
}
|
125 |
|
|
|
126 |
|
|
#else
|
127 |
|
|
|
128 |
|
|
// An alternative implementation that overloads the SIGALRM handler
|
129 |
|
|
// rather than using SIGPROF. It does not seem to work any better.
|
130 |
|
|
static void (*synth_profile_old_alrm_sighandler)(int);
|
131 |
|
|
|
132 |
|
|
static void
|
133 |
|
|
synth_profile_alrm_sighandler(int sig, struct cyg_hal_sys_sigcontext context)
|
134 |
|
|
{
|
135 |
|
|
__profile_hit((CYG_ADDRWORD) context.hal_eip);
|
136 |
|
|
(*synth_profile_old_alrm_sighandler)(sig);
|
137 |
|
|
}
|
138 |
|
|
|
139 |
|
|
int
|
140 |
|
|
hal_enable_profile_timer(int resolution)
|
141 |
|
|
{
|
142 |
|
|
struct cyg_hal_sys_sigaction action;
|
143 |
|
|
|
144 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, (const struct cyg_hal_sys_sigaction*)0, &action)) {
|
145 |
|
|
CYG_FAIL("Failed to retrieve old signal handler for SIGALRM");
|
146 |
|
|
}
|
147 |
|
|
synth_profile_old_alrm_sighandler = action.hal_handler;
|
148 |
|
|
action.hal_handler = (void (*)(int)) &synth_profile_alrm_sighandler;
|
149 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, &action, (struct cyg_hal_sys_sigaction*)0)) {
|
150 |
|
|
CYG_FAIL("Failed to install new signal handler for SIGALRM");
|
151 |
|
|
}
|
152 |
|
|
|
153 |
|
|
return CYGNUM_HAL_RTC_PERIOD;
|
154 |
|
|
}
|
155 |
|
|
|
156 |
|
|
#endif
|
157 |
|
|
|
158 |
|
|
// mcount() can be implemented largely using compiler built-ins. However
|
159 |
|
|
// there are two complications. The generic profiling code assumes
|
160 |
|
|
// __profile_mcount() is called with interrupts disabled. Blocking interrupts
|
161 |
|
|
// won't stop the low-level signal handlers, so mcount() calls from those
|
162 |
|
|
// may get lost because of the nesting test but that is fairly harmless.
|
163 |
|
|
// Those signal handlers will complete before control returns here, i.e.
|
164 |
|
|
// we have strict nesting, so there is no risk of the nested flag remaining
|
165 |
|
|
// set while a context switch occurs. Also if eCos itself is built with
|
166 |
|
|
// -pg then the compiler will insert a recursive call to mcount(), and
|
167 |
|
|
// we have to guard against that.
|
168 |
|
|
void
|
169 |
|
|
mcount(void)
|
170 |
|
|
{
|
171 |
|
|
static int nested = 0;
|
172 |
|
|
int enabled;
|
173 |
|
|
|
174 |
|
|
HAL_DISABLE_INTERRUPTS(enabled);
|
175 |
|
|
if (!nested) {
|
176 |
|
|
nested = 1;
|
177 |
|
|
__profile_mcount((CYG_ADDRWORD)__builtin_return_address(1),
|
178 |
|
|
(CYG_ADDRWORD)__builtin_return_address(0));
|
179 |
|
|
nested = 0;
|
180 |
|
|
}
|
181 |
|
|
HAL_RESTORE_INTERRUPTS(enabled);
|
182 |
|
|
}
|
183 |
|
|
|
184 |
|
|
#endif
|