Home | History | Annotate | Download | only in perf_event_open
      1 /******************************************************************************/
      2 /*                                                                            */
      3 /* Ingo Molnar <mingo (at) 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 "lapi/syscalls.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 
     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 
    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 
    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 
    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 
    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 		    TEST_ERRNO == ENODEV) {
    154 			tst_resm(TCONF | TTERRNO,
    155 			         "perf_event_open for %s not supported",
    156 			         tc->config_name);
    157 		} else {
    158 			tst_brkm(TFAIL | TTERRNO, cleanup,
    159 				 "perf_event_open %s failed unexpectedly",
    160 				 tc->config_name);
    161 		}
    162 		return;
    163 	}
    164 
    165 	fd = TEST_RETURN;
    166 
    167 	if (ioctl(fd, PERF_EVENT_IOC_RESET, 0) == -1) {
    168 		tst_brkm(TFAIL | TTERRNO, cleanup,
    169 			 "ioctl set PERF_EVENT_IOC_RESET failed");
    170 	}
    171 
    172 	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) {
    173 		tst_brkm(TFAIL | TTERRNO, cleanup,
    174 			 "ioctl set PERF_EVENT_IOC_ENABLE failed");
    175 	}
    176 
    177 	do_work();
    178 
    179 	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) == -1) {
    180 		tst_brkm(TFAIL | TTERRNO, cleanup,
    181 			 "ioctl set PERF_EVENT_IOC_RESET failed");
    182 	}
    183 
    184 	ret = read(fd, &count, sizeof(count));
    185 	if (ret == sizeof(count)) {
    186 		tst_resm(TINFO, "read event counter succeeded, "
    187 			 "value: %llu", count);
    188 		tst_resm(TPASS, "test PERF_TYPE_HARDWARE: %s succeeded",
    189 			 tc->config_name);
    190 	} else {
    191 		tst_resm(TFAIL | TERRNO, "read event counter failed");
    192 	}
    193 
    194 	SAFE_CLOSE(cleanup, fd);
    195 
    196 }
    197 
    198 static void cleanup(void)
    199 {
    200 }
    201 
    202 #else
    203 
    204 int main(void)
    205 {
    206 	tst_brkm(TCONF, NULL, "This system doesn't have "
    207 		 "header file:<linux/perf_event.h> or "
    208 		 "no struct perf_event_attr defined");
    209 }
    210 #endif
    211