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.
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
36 #include "intercept.h"
37 #include "mi-perfctr.h"
38 #include "memintercept.h"
39 #include "memintercept-utils.h"
40 #include "stack-frame.h"
42 static int perfctr_fd
= -1;
47 #define MI_DEBUG(arg) mi_debug arg
48 #else /* !ENABLE_DEBUG */
49 #define MI_DEBUG(arg) (void)0
50 #endif /* ENABLE_DEBUG */
52 /* External declaration */
54 #define SIGHANDLER_FRAMES 2
57 sigprof_handler (int unused
, siginfo_t
*si
, ucontext_t
*ucontext
)
59 int saved_errno
= errno
;
60 struct sigcontext
*ctx
= (struct sigcontext
*)&ucontext
->uc_mcontext
;
63 info
.alloc
.operation
= MI_TIME
;
64 info
.alloc
.old_ptr
= NULL
;
65 info
.alloc
.new_ptr
= NULL
;
68 mi_call_with_signal_backtrace ((void *)ctx
->EIPRIP
, (void *)ctx
->EBPRBP
,
69 (void *)ctx
->ESPRSP
, mi_write_stack
, &info
);
71 if (ioctl (perfctr_fd
, VPERFCTR_IRESUME
) < 0)
72 mi_perror ("Error restarting handler interrupt");
78 init_sighandler (void)
81 sa
.sa_handler
= (void (*)(int))sigprof_handler
;
82 sigemptyset (&sa
.sa_mask
);
83 sa
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
84 if (sigaction (SIGPROF
, &sa
, NULL
) != 0) {
85 mi_perror ("Error setting up signal handler\n");
93 mi_perfctr_start (int interval
)
95 struct perfctr_info info
;
96 struct vperfctr_control control
;
98 MI_DEBUG (("Turning on performance monitoring timer support\n"));
100 if ((perfctr_fd
= open ("/proc/self/perfctr", O_RDONLY
)) < 0) {
101 mi_perror ("Error opening /proc/self/perfctr");
105 if (ioctl (perfctr_fd
, PERFCTR_INFO
, &info
) < 0) {
106 mi_perror ("Error getting perfctr information");
110 if (!(info
.cpu_features
& PERFCTR_FEATURE_PCINT
)) {
111 mi_debug ("Performance monitoring interrupts not found\n");
115 if (info
.cpu_type
!= PERFCTR_X86_INTEL_PII
&&
116 info
.cpu_type
!= PERFCTR_X86_INTEL_PIII
) {
117 mi_debug ("Only support PII and PIII performance monitoring counters, found %d\n", info
.cpu_type
);
121 memset(&control
, 0, sizeof control
);
123 control
.si_signo
= SIGPROF
;
124 control
.cpu_control
.nractrs
= 0;
125 control
.cpu_control
.nrictrs
= 1;
126 control
.cpu_control
.tsc_on
= 1;
127 control
.cpu_control
.pmc_map
[0] = 0;
128 /* CPU_CLK_UNHALTED, USR, ENable, INT */
129 control
.cpu_control
.evntsel
[0] = 0x79 | (1 << 16) | (1 << 22) | (1 << 20);
130 control
.cpu_control
.ireset
[0] = - (int) (0.5 + (info
.cpu_khz
/ 1000.) * interval
);
132 if (ioctl (perfctr_fd
, VPERFCTR_CONTROL
, &control
) < 0) {
133 mi_perror ("Error setting up performance monitoring counters");
137 return init_sighandler ();
140 if (perfctr_fd
!= -1)
147 mi_perfctr_stop (void)