• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /*                                                                            */
3 /* Ingo Molnar <mingo@elte.hu>, 2009                                          */
4 /*                                                                            */
5 /* This program is free software;  you can redistribute it and/or modify      */
6 /* it under the terms of the GNU General Public License as published by       */
7 /* the Free Software Foundation; either version 2 of the License, or          */
8 /* (at your option) any later version.                                        */
9 /*                                                                            */
10 /* This program is distributed in the hope that it will be useful,            */
11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
13 /* the GNU General Public License for more details.                           */
14 /*                                                                            */
15 /* You should have received a copy of the GNU General Public License          */
16 /* along with this program;  if not, write to the Free Software               */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
18 /*                                                                            */
19 /******************************************************************************/
20 
21 /*
22  * Very simple performance counter testcase.
23  * Picked up from: http://lkml.org/lkml/2008/12/5/17
24  */
25 
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 #include <sys/stat.h>
29 #include <sys/time.h>
30 #include <sys/uio.h>
31 #include <linux/unistd.h>
32 #include <assert.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <stdint.h>
40 #include "config.h"
41 #if HAVE_PERF_EVENT_ATTR
42 # include <linux/perf_event.h>
43 #endif
44 
45 #include "test.h"
46 #include "linux_syscall_numbers.h"
47 #include "safe_macros.h"
48 
49 char *TCID = "perf_event_open01";
50 
51 #if HAVE_PERF_EVENT_ATTR
52 static void setup(void);
53 static void cleanup(void);
54 
55 static struct test_case_t {
56 	uint32_t type;
57 	const char *config_name;
58 	unsigned long long config;
59 } event_types[] = {
60 	{ PERF_TYPE_HARDWARE, "PERF_COUNT_HW_INSTRUCTIONS",
61 	  PERF_COUNT_HW_INSTRUCTIONS },
62 	{ PERF_TYPE_HARDWARE, "PERF_COUNT_HW_CACHE_REFERENCES",
63 	  PERF_COUNT_HW_CACHE_REFERENCES },
64 	{ PERF_TYPE_HARDWARE, "PERF_COUNT_HW_CACHE_MISSES",
65 	  PERF_COUNT_HW_CACHE_MISSES },
66 	{ PERF_TYPE_HARDWARE, "PERF_COUNT_HW_BRANCH_INSTRUCTIONS",
67 	  PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
68 	{ PERF_TYPE_HARDWARE, "PERF_COUNT_HW_BRANCH_MISSES",
69 	  PERF_COUNT_HW_BRANCH_MISSES },
70 	{ PERF_TYPE_SOFTWARE, "PERF_COUNT_SW_CPU_CLOCK",
71 	  PERF_COUNT_SW_CPU_CLOCK },
72 	{ PERF_TYPE_SOFTWARE, "PERF_COUNT_SW_TASK_CLOCK",
73 	  PERF_COUNT_SW_TASK_CLOCK },
74 };
75 
76 int TST_TOTAL = ARRAY_SIZE(event_types);
77 
78 static void verify(struct test_case_t *tc);
79 static struct perf_event_attr pe;
80 
main(int ac,char ** av)81 int main(int ac, char **av)
82 {
83 	int i, lc;
84 
85 	tst_parse_opts(ac, av, NULL, NULL);
86 
87 	setup();
88 
89 	for (lc = 0; TEST_LOOPING(lc); lc++) {
90 		tst_count = 0;
91 
92 		for (i = 0; i < TST_TOTAL; i++)
93 			verify(&event_types[i]);
94 	}
95 
96 	cleanup();
97 	tst_exit();
98 }
99 
setup(void)100 static void setup(void)
101 {
102 	/*
103 	 * According to perf_event_open's manpage, the official way of
104 	 * knowing if perf_event_open() support is enabled is checking for
105 	 * the existence of the file /proc/sys/kernel/perf_event_paranoid.
106 	 */
107 	if (access("/proc/sys/kernel/perf_event_paranoid", F_OK) == -1)
108 		tst_brkm(TCONF, NULL, "Kernel doesn't have perf_event support");
109 
110 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
111 
112 	TEST_PAUSE;
113 
114 	pe.size = sizeof(struct perf_event_attr);
115 	pe.disabled = 1;
116 	pe.exclude_kernel = 1;
117 	pe.exclude_hv = 1;
118 }
119 
120 
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)121 static int perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
122 		int cpu, int group_fd, unsigned long flags)
123 {
124 	int ret;
125 
126 	ret = ltp_syscall(__NR_perf_event_open, hw_event, pid, cpu,
127 			  group_fd, flags);
128 	return ret;
129 }
130 
131 /* do_work() is copied form performance_counter02.c */
132 #define LOOPS	100000000
133 
do_work(void)134 static void do_work(void)
135 {
136 	int i;
137 
138 	for (i = 0; i < LOOPS; ++i)
139 		asm volatile ("" : : "g" (i));
140 }
141 
verify(struct test_case_t * tc)142 static void verify(struct test_case_t *tc)
143 {
144 	unsigned long long count;
145 	int fd, ret;
146 
147 	pe.type = tc->type;
148 	pe.config = tc->config;
149 
150 	TEST(perf_event_open(&pe, 0, -1, -1, 0));
151 	if (TEST_RETURN == -1) {
152 		if (TEST_ERRNO == ENOENT || TEST_ERRNO == EOPNOTSUPP) {
153 			tst_resm(TCONF | TTERRNO,
154 			         "perf_event_open for %s not supported",
155 			         tc->config_name);
156 		} else {
157 			tst_brkm(TFAIL | TTERRNO, cleanup,
158 				 "perf_event_open %s failed unexpectedly",
159 				 tc->config_name);
160 		}
161 		return;
162 	}
163 
164 	fd = TEST_RETURN;
165 
166 	if (ioctl(fd, PERF_EVENT_IOC_RESET, 0) == -1) {
167 		tst_brkm(TFAIL | TTERRNO, cleanup,
168 			 "ioctl set PERF_EVENT_IOC_RESET failed");
169 	}
170 
171 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) {
172 		tst_brkm(TFAIL | TTERRNO, cleanup,
173 			 "ioctl set PERF_EVENT_IOC_ENABLE failed");
174 	}
175 
176 	do_work();
177 
178 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) == -1) {
179 		tst_brkm(TFAIL | TTERRNO, cleanup,
180 			 "ioctl set PERF_EVENT_IOC_RESET failed");
181 	}
182 
183 	ret = read(fd, &count, sizeof(count));
184 	if (ret == sizeof(count)) {
185 		tst_resm(TINFO, "read event counter succeeded, "
186 			 "value: %llu", count);
187 		tst_resm(TPASS, "test PERF_TYPE_HARDWARE: %s succeeded",
188 			 tc->config_name);
189 	} else {
190 		tst_resm(TFAIL | TERRNO, "read event counter failed");
191 	}
192 
193 	SAFE_CLOSE(cleanup, fd);
194 
195 }
196 
cleanup(void)197 static void cleanup(void)
198 {
199 }
200 
201 #else
202 
main(void)203 int main(void)
204 {
205 	tst_brkm(TCONF, NULL, "This system doesn't have "
206 		 "header file:<linux/perf_event.h> or "
207 		 "no struct perf_event_attr defined");
208 }
209 #endif
210