subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 1 | /******************************************************************************/ |
| 2 | /* */ |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 3 | /* Ingo Molnar <mingo@elte.hu>, 2009 */ |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 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 */ |
Wanlong Gao | 4548c6c | 2012-10-19 18:03:36 +0800 | [diff] [blame] | 17 | /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 18 | /* */ |
| 19 | /******************************************************************************/ |
| 20 | |
| 21 | /* |
| 22 | * Very simple performance counter testcase. |
| 23 | * Picked up from: http://lkml.org/lkml/2008/12/5/17 |
| 24 | */ |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 25 | |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 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> |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 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> |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 39 | #include <stdint.h> |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 40 | #include "config.h" |
| 41 | #if HAVE_PERF_EVENT_ATTR |
| 42 | # include <linux/perf_event.h> |
| 43 | #endif |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 44 | |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 45 | #include "test.h" |
subrata_modak | d076204 | 2009-06-23 14:21:32 +0000 | [diff] [blame] | 46 | #include "linux_syscall_numbers.h" |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 47 | #include "safe_macros.h" |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 48 | |
Xing Gu | 166c45f | 2014-08-07 10:05:01 +0800 | [diff] [blame] | 49 | char *TCID = "perf_event_open01"; |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 50 | |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 51 | #if HAVE_PERF_EVENT_ATTR |
| 52 | static void setup(void); |
| 53 | static void cleanup(void); |
| 54 | |
| 55 | static struct test_case_t { |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 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", |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 67 | PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 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 }, |
subrata_modak | d179151 | 2009-04-02 06:46:36 +0000 | [diff] [blame] | 74 | }; |
| 75 | |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 76 | int TST_TOTAL = ARRAY_SIZE(event_types); |
| 77 | |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 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; |
Cyril Hrubis | 0b9589f | 2014-05-27 17:40:33 +0200 | [diff] [blame] | 84 | const char *msg; |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 85 | |
| 86 | msg = parse_opts(ac, av, NULL, NULL); |
| 87 | if (msg != NULL) |
| 88 | tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
| 89 | |
| 90 | setup(); |
| 91 | |
| 92 | for (lc = 0; TEST_LOOPING(lc); lc++) { |
| 93 | tst_count = 0; |
| 94 | |
| 95 | for (i = 0; i < TST_TOTAL; i++) |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 96 | verify(&event_types[i]); |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | cleanup(); |
| 100 | tst_exit(); |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 101 | } |
yaberauneya | 1a1b1fb | 2009-11-27 08:15:35 +0000 | [diff] [blame] | 102 | |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 103 | static void setup(void) |
| 104 | { |
| 105 | /* |
| 106 | * According to perf_event_open's manpage, the official way of |
| 107 | * knowing if perf_event_open() support is enabled is checking for |
| 108 | * the existence of the file /proc/sys/kernel/perf_event_paranoid. |
| 109 | */ |
| 110 | if (access("/proc/sys/kernel/perf_event_paranoid", F_OK) == -1) |
| 111 | tst_brkm(TCONF, NULL, "Kernel doesn't have perf_event support"); |
| 112 | |
| 113 | tst_sig(NOFORK, DEF_HANDLER, cleanup); |
| 114 | |
| 115 | TEST_PAUSE; |
| 116 | |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 117 | pe.size = sizeof(struct perf_event_attr); |
| 118 | pe.disabled = 1; |
| 119 | pe.exclude_kernel = 1; |
| 120 | pe.exclude_hv = 1; |
| 121 | } |
| 122 | |
| 123 | |
| 124 | static int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, |
| 125 | int cpu, int group_fd, unsigned long flags) |
| 126 | { |
| 127 | int ret; |
| 128 | |
| 129 | ret = ltp_syscall(__NR_perf_event_open, hw_event, pid, cpu, |
| 130 | group_fd, flags); |
| 131 | return ret; |
| 132 | } |
| 133 | |
| 134 | /* do_work() is copied form performance_counter02.c */ |
| 135 | #define LOOPS 1000000000 |
| 136 | |
| 137 | static void do_work(void) |
| 138 | { |
| 139 | int i; |
| 140 | |
| 141 | for (i = 0; i < LOOPS; ++i) |
| 142 | asm volatile ("" : : "g" (i)); |
| 143 | } |
| 144 | |
| 145 | static void verify(struct test_case_t *tc) |
| 146 | { |
| 147 | unsigned long long count; |
| 148 | int fd, ret; |
| 149 | |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 150 | pe.type = tc->type; |
| 151 | pe.config = tc->config; |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 152 | |
| 153 | TEST(perf_event_open(&pe, 0, -1, -1, 0)); |
| 154 | if (TEST_RETURN == -1) { |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 155 | if (TEST_ERRNO == ENOENT) { |
| 156 | tst_resm(TCONF, |
| 157 | "perf_event_open for %s not supported", |
| 158 | tc->config_name); |
| 159 | } else { |
| 160 | tst_brkm(TFAIL | TTERRNO, cleanup, |
| 161 | "perf_event_open failed unexpectedly"); |
| 162 | } |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 163 | return; |
| 164 | } |
| 165 | |
| 166 | fd = TEST_RETURN; |
| 167 | |
| 168 | if (ioctl(fd, PERF_EVENT_IOC_RESET, 0) == -1) { |
| 169 | tst_brkm(TFAIL | TTERRNO, cleanup, |
| 170 | "ioctl set PERF_EVENT_IOC_RESET failed"); |
| 171 | } |
| 172 | |
| 173 | if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) { |
| 174 | tst_brkm(TFAIL | TTERRNO, cleanup, |
| 175 | "ioctl set PERF_EVENT_IOC_ENABLE failed"); |
| 176 | } |
| 177 | |
| 178 | do_work(); |
| 179 | |
| 180 | if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) == -1) { |
| 181 | tst_brkm(TFAIL | TTERRNO, cleanup, |
| 182 | "ioctl set PERF_EVENT_IOC_RESET failed"); |
| 183 | } |
| 184 | |
| 185 | ret = read(fd, &count, sizeof(count)); |
| 186 | if (ret == sizeof(count)) { |
| 187 | tst_resm(TINFO, "read event counter succeeded, " |
| 188 | "value: %llu", count); |
| 189 | tst_resm(TPASS, "test PERF_TYPE_HARDWARE: %s succeeded", |
Cyril Hrubis | adedb78 | 2014-08-21 11:20:12 +0200 | [diff] [blame] | 190 | tc->config_name); |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 191 | } else { |
| 192 | tst_resm(TFAIL | TERRNO, "read event counter failed"); |
| 193 | } |
| 194 | |
| 195 | SAFE_CLOSE(cleanup, fd); |
| 196 | |
| 197 | } |
| 198 | |
| 199 | static void cleanup(void) |
| 200 | { |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | #else |
| 204 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 205 | int main(void) |
| 206 | { |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 207 | tst_brkm(TCONF, NULL, "This system doesn't have " |
| 208 | "header file:<linux/perf_event.h> or " |
| 209 | "no struct perf_event_attr defined"); |
Garrett Cooper | 49f7622 | 2010-12-19 10:22:13 -0800 | [diff] [blame] | 210 | } |
Xiaoguang Wang | 7e6be18 | 2014-04-10 12:08:45 +0800 | [diff] [blame] | 211 | #endif |