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