1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 1999, 2000, 2001, Red Hat, Inc.
5 * Copyright 2002, Kristian Rietveld
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #define MI_DEBUG(arg) mi_debug arg
29 #else /* !ENABLE_DEBUG */
30 #define MI_DEBUG(arg) (void)0
31 #endif /* ENABLE_DEBUG */
39 #include <sys/ioctl.h>
42 #include <linux/rtc.h>
44 #include "intercept.h"
45 #include "memintercept.h"
46 #include "memintercept-utils.h"
47 #include "mi-perfctr.h"
48 #include "stack-frame.h"
50 static void init_sighandler (int signum
);
52 static int timer_fd
= -1;
53 static int profile_interval
= 10000; /* In usecs */
61 static SpeedProfType profile_type
;
64 start_rtc_timer (void)
69 MI_DEBUG (("Turning on RTC timer\n"));
71 if ((timer_fd
= open ("/dev/rtc", O_RDONLY
)) < 0) {
72 mi_perror ("Error opening /dev/rtc");
76 flags
= fcntl (timer_fd
, F_GETFL
);
77 if (fcntl (timer_fd
, F_SETFL
, flags
| FASYNC
) < 0) {
78 mi_perror ("Error setting FASYNC");
81 if (fcntl (timer_fd
, F_SETOWN
, getpid ()) < 0) {
82 mi_perror ("Error setting owner for SIGIO");
85 if (fcntl (timer_fd
, F_SETSIG
, SIGPROF
) < 0) {
86 mi_perror ("Error setting signal for /dev/rtc");
91 while (1000000 / irq_rate
> profile_interval
&&
95 if (ioctl (timer_fd
, RTC_IRQP_SET
, irq_rate
) < 0) {
96 mi_perror ("Error setting interrupt rate");
99 if (ioctl (timer_fd
, RTC_PIE_ON
) < 0) {
100 mi_perror ("Error turning on interrupts");
104 init_sighandler (SIGPROF
);
113 stop_rtc_timer (void)
115 if (timer_fd
!= -1) {
116 if (ioctl (timer_fd
, RTC_PIE_OFF
) < 0)
117 mi_perror ("Error turning off interrupts");
119 if (close (timer_fd
) < 0)
120 mi_perror ("Error closing /dev/rtc");
124 static int profile_itimer_type
;
127 reset_itimer_timer (void)
129 struct itimerval it
, tem
;
130 it
.it_interval
.tv_usec
= 0;
131 it
.it_interval
.tv_sec
= 0;
132 it
.it_value
.tv_usec
= profile_interval
% 1000000;
133 it
.it_value
.tv_sec
= profile_interval
/ 1000000;
134 if (setitimer (profile_itimer_type
, &it
, &tem
) != 0) {
135 mi_perror ("Error setting up itimer");
143 start_itimer_timer (int timer_type
)
145 profile_itimer_type
= timer_type
;
146 if (!reset_itimer_timer ())
149 init_sighandler (timer_type
== ITIMER_PROF
? SIGPROF
: SIGALRM
);
155 #define SIGHANDLER_FRAMES 2
158 #if defined (__linux__)
159 sigprof_handler (int unused
, struct sigcontext ctx
)
161 sigprof_handler (int unused
)
164 int saved_errno
= errno
;
167 info
.alloc
.operation
= MI_TIME
;
168 info
.alloc
.old_ptr
= NULL
;
169 info
.alloc
.new_ptr
= NULL
;
172 #if defined (__linux__)
173 mi_call_with_signal_backtrace ((void *)ctx
.EIPRIP
, (void *)ctx
.EBPRBP
,
174 (void *)ctx
.ESPRSP
, mi_write_stack
, &info
);
176 mi_call_with_backtrace (SIGHANDLER_FRAMES
, saved_pc
, mi_write_stack
, &info
);
179 if (profile_type
== SPEED_PROF_ITIMER
)
180 reset_itimer_timer ();
185 init_sighandler (int signum
)
188 sa
.sa_handler
= (void (*)(int))sigprof_handler
;
189 sigemptyset (&sa
.sa_mask
);
190 sa
.sa_flags
= SA_RESTART
;
191 if (sigaction (signum
, &sa
, 0) != 0)
192 mi_perror ("Error setting up signal handler");
203 const char *type_string
;
204 const char *interval_string
;
208 interval_string
= getenv ("_MEMPROF_INTERVAL");
209 if (!interval_string
)
210 interval_string
= "10000";
212 profile_interval
= strtol (interval_string
, &end
, 10);
213 if (*interval_string
== '\0' || *end
!= '\0' || profile_interval
<= 0) {
214 mi_debug ("Invalid interval %s\n", interval_string
);
215 profile_interval
= 10000;
218 type_string
= getenv ("_MEMPROF_SPEED_TYPE");
220 type_string
= "cycles";
222 if (strcmp (type_string
, "time") == 0) {
223 if (start_rtc_timer ())
224 profile_type
= SPEED_PROF_RTC
;
225 else if (start_itimer_timer (ITIMER_REAL
))
226 profile_type
= SPEED_PROF_ITIMER
;
230 } else if (strcmp (type_string
, "cycles") == 0) {
231 if (mi_perfctr_start (profile_interval
))
232 profile_type
= SPEED_PROF_PERFCTR
;
233 else if (start_itimer_timer (ITIMER_PROF
))
234 profile_type
= SPEED_PROF_ITIMER
;
238 mi_debug ("Unknown value for _MEMPROF_SPEED_TYPE: %s\n");
243 mi_debug ("Couldn't start timer\n");
251 switch (profile_type
) {
255 case SPEED_PROF_PERFCTR
:
258 case SPEED_PROF_ITIMER
: