src/main.c: Make it possible to pass options to the app under test
[memprof.git] / lib / mi-perfctr.c
blob1d386da59a22b4a818eafdcbffaa0503c8d0e57f
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.
21 /*====*/
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <ucontext.h>
32 #include <unistd.h>
34 #include "perfctr.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;
44 #undef ENABLE_DEBUG
46 #ifdef ENABLE_DEBUG
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 */
53 /* XXX hmm.. */
54 #define SIGHANDLER_FRAMES 2
56 static void
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;
61 MIInfo info;
63 info.alloc.operation = MI_TIME;
64 info.alloc.old_ptr = NULL;
65 info.alloc.new_ptr = NULL;
66 info.alloc.size = 1;
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");
74 errno = saved_errno;
77 static MIBool
78 init_sighandler (void)
80 struct sigaction sa;
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");
86 return MI_FALSE;
89 return MI_TRUE;
92 MIBool
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");
102 goto bail;
105 if (ioctl (perfctr_fd, PERFCTR_INFO, &info) < 0) {
106 mi_perror ("Error getting perfctr information");
107 goto bail;
110 if (!(info.cpu_features & PERFCTR_FEATURE_PCINT)) {
111 mi_debug ("Performance monitoring interrupts not found\n");
112 goto bail;
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);
118 goto bail;
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");
134 goto bail;
137 return init_sighandler ();
139 bail:
140 if (perfctr_fd != -1)
141 close (perfctr_fd);
143 return MI_FALSE;
146 void
147 mi_perfctr_stop (void)