blob: 5402b818167e3b045e48f7af1b4508bf4927838e [file] [log] [blame]
subrata_modak89823fe2009-04-02 06:48:41 +00001/******************************************************************************/
2/* */
3/* Paul Mackerras <paulus@samba.org>, 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 */
Wanlong Gao4548c6c2012-10-19 18:03:36 +080017/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
subrata_modak89823fe2009-04-02 06:48:41 +000018/* */
19/******************************************************************************/
20/*
21Here's a little test program that checks whether software counters
22(specifically, the task clock counter) work correctly when they're in
23a group with hardware counters.
24
25What it does is to create several groups, each with one hardware
26counter, counting instructions, plus a task clock counter. It needs
27to know an upper bound N on the number of hardware counters you have
28(N defaults to 8), and it creates N+4 groups to force them to be
29multiplexed. It also creates an overall task clock counter.
30
31Then it spins for a while, and then stops all the counters and reads
32them. It takes the total of the task clock counters in the groups and
33computes the ratio of that total to the overall execution time from
34the overall task clock counter.
35
36That ratio should be equal to the number of actual hardware counters
37that can count instructions. If the task clock counters in the groups
38don't stop when their group gets taken off the PMU, the ratio will
39instead be close to N+4. The program will declare that the test fails
40if the ratio is greater than N (actually, N + 0.0001 to allow for FP
41rounding errors).
42
43Could someone run this on x86 on the latest PCL tree and let me know
44what happens? I don't have an x86 crash box easily to hand. On
45powerpc, it passes, but I think that is because I am missing setting
46counter->prev_count in arch/powerpc/kernel/perf_counter.c, and I think
47that means that enabling/disabling a group with a task clock counter
48in it won't work correctly (I'll do a test program for that next).
49
50Usage is: ./performance_counter02 [-c num-hw-counters] [-v]
51
52Use -c N if you have more than 8 hardware counters. The -v flag makes
53it print out the values of each counter.
54*/
55
subrata_modak89823fe2009-04-02 06:48:41 +000056#include <stdio.h>
57#include <stddef.h>
58#include <stdlib.h>
59#include <string.h>
60#include <fcntl.h>
61#include <poll.h>
62#include <unistd.h>
63#include <errno.h>
yaberauneyaef772532009-10-09 17:55:43 +000064#include "config.h"
65#include <sys/prctl.h>
subrata_modak89823fe2009-04-02 06:48:41 +000066#include <sys/types.h>
67#include <linux/types.h>
subrata_modak89823fe2009-04-02 06:48:41 +000068
69/* Harness Specific Include Files. */
70#include "test.h"
71#include "usctest.h"
subrata_modakd0762042009-06-23 14:21:32 +000072#include "linux_syscall_numbers.h"
subrata_modak89823fe2009-04-02 06:48:41 +000073
74#define PR_TASK_PERF_COUNTERS_DISABLE 31
75#define PR_TASK_PERF_COUNTERS_ENABLE 32
76
subrata_modak89823fe2009-04-02 06:48:41 +000077/* Global Variables */
Wanlong Gao354ebb42012-12-07 10:10:04 +080078char *TCID = "performance_counter02"; /* test program identifier. */
79int TST_TOTAL = 1; /* total number of tests in this file. */
subrata_modak89823fe2009-04-02 06:48:41 +000080
subrata_modak89823fe2009-04-02 06:48:41 +000081typedef unsigned int u32;
82typedef unsigned long long u64;
83typedef long long s64;
84
85struct perf_counter_hw_event {
Wanlong Gao354ebb42012-12-07 10:10:04 +080086 s64 type;
87 u64 irq_period;
88 u32 record_type;
subrata_modak89823fe2009-04-02 06:48:41 +000089
Wanlong Gao354ebb42012-12-07 10:10:04 +080090 u32 disabled:1, /* off by default */
91 nmi:1, /* NMI sampling */
92 raw:1, /* raw event type */
93 __reserved_1:29;
94 u64 __reserved_2;
subrata_modak89823fe2009-04-02 06:48:41 +000095};
96
97enum hw_event_types {
Wanlong Gao354ebb42012-12-07 10:10:04 +080098 PERF_COUNT_CYCLES = 0,
99 PERF_COUNT_INSTRUCTIONS = 1,
100 PERF_COUNT_CACHE_REFERENCES = 2,
101 PERF_COUNT_CACHE_MISSES = 3,
102 PERF_COUNT_BRANCH_INSTRUCTIONS = 4,
103 PERF_COUNT_BRANCH_MISSES = 5,
subrata_modak89823fe2009-04-02 06:48:41 +0000104
105 /*
106 * Special "software" counters provided by the kernel, even if
107 * the hardware does not support performance counters. These
108 * counters measure various physical and sw events of the
109 * kernel (and allow the profiling of them as well):
110 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800111 PERF_COUNT_CPU_CLOCK = -1,
112 PERF_COUNT_TASK_CLOCK = -2,
subrata_modak89823fe2009-04-02 06:48:41 +0000113 /*
114 * Future software events:
115 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800116 /* PERF_COUNT_PAGE_FAULTS = -3,
117 PERF_COUNT_CONTEXT_SWITCHES = -4, */
subrata_modak89823fe2009-04-02 06:48:41 +0000118};
119
120int sys_perf_counter_open(struct perf_counter_hw_event *hw_event,
121 pid_t pid, int cpu, int group_fd, unsigned long flags)
122{
Jan Stancek359980f2013-02-15 10:16:05 +0100123 return ltp_syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd,
subrata_modak89823fe2009-04-02 06:48:41 +0000124 flags);
125}
126
127#define MAX_CTRS 50
128#define LOOPS 1000000000
129
130void do_work(void)
131{
132 int i;
133
134 for (i = 0; i < LOOPS; ++i)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800135 asm volatile (""::"g" (i));
subrata_modak89823fe2009-04-02 06:48:41 +0000136}
137
Wanlong Gao354ebb42012-12-07 10:10:04 +0800138void cleanup(void)
139{ /* Stub function. */
140}
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000141
Wanlong Gao354ebb42012-12-07 10:10:04 +0800142int main(int ac, char **av)
subrata_modak89823fe2009-04-02 06:48:41 +0000143{
144 int tsk0;
145 int hwfd[MAX_CTRS], tskfd[MAX_CTRS];
146 struct perf_counter_hw_event tsk_event;
147 struct perf_counter_hw_event hw_event;
148 unsigned long long vt0, vt[MAX_CTRS], vh[MAX_CTRS], vtsum, vhsum;
149 int i, n, nhw;
150 int verbose = 0;
151 double ratio;
152
153 nhw = 8;
154 while ((i = getopt(ac, av, "c:v")) != -1) {
155 switch (i) {
156 case 'c':
157 n = atoi(optarg);
158 break;
159 case 'v':
160 verbose = 1;
161 break;
162 case '?':
163 fprintf(stderr, "Usage: %s [-c #hwctrs] [-v]\n", av[0]);
164 exit(1);
165 }
166 }
167
168 if (nhw < 0 || nhw > MAX_CTRS - 4) {
169 fprintf(stderr, "invalid number of hw counters specified: %d\n",
170 nhw);
171 exit(1);
172 }
173
174 n = nhw + 4;
175
176 memset(&tsk_event, 0, sizeof(tsk_event));
177 tsk_event.type = PERF_COUNT_TASK_CLOCK;
178 tsk_event.disabled = 1;
179
180 memset(&hw_event, 0, sizeof(hw_event));
181 hw_event.disabled = 1;
182 hw_event.type = PERF_COUNT_INSTRUCTIONS;
183
184 tsk0 = sys_perf_counter_open(&tsk_event, 0, -1, -1, 0);
185 if (tsk0 == -1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800186 tst_brkm(TBROK | TERRNO, cleanup,
187 "perf_counter_open failed (1)");
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000188 } else {
subrata_modak89823fe2009-04-02 06:48:41 +0000189
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000190 tsk_event.disabled = 0;
191 for (i = 0; i < n; ++i) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800192 hwfd[i] = sys_perf_counter_open(&hw_event, 0, -1,
193 -1, 0);
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000194 tskfd[i] = sys_perf_counter_open(&tsk_event, 0, -1,
195 hwfd[i], 0);
196 if (tskfd[i] == -1 || hwfd[i] == -1) {
197 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800198 "perf_counter_open failed (2)");
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000199 }
subrata_modak89823fe2009-04-02 06:48:41 +0000200 }
201 }
202
203 prctl(PR_TASK_PERF_COUNTERS_ENABLE);
204 do_work();
205 prctl(PR_TASK_PERF_COUNTERS_DISABLE);
206
207 if (read(tsk0, &vt0, sizeof(vt0)) != sizeof(vt0)) {
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000208 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800209 "error reading task clock counter");
subrata_modak89823fe2009-04-02 06:48:41 +0000210 }
211
212 vtsum = vhsum = 0;
213 for (i = 0; i < n; ++i) {
214 if (read(tskfd[i], &vt[i], sizeof(vt[i])) != sizeof(vt[i]) ||
215 read(hwfd[i], &vh[i], sizeof(vh[i])) != sizeof(vh[i])) {
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000216 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800217 "error reading counter(s)");
subrata_modak89823fe2009-04-02 06:48:41 +0000218 }
219 vtsum += vt[i];
220 vhsum += vh[i];
221 }
222
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000223 tst_resm(TINFO, "overall task clock: %lld", vt0);
224 tst_resm(TINFO, "hw sum: %lld, task clock sum: %lld", vhsum, vtsum);
subrata_modak89823fe2009-04-02 06:48:41 +0000225 if (verbose) {
226 printf("hw counters:");
227 for (i = 0; i < n; ++i)
228 printf(" %lld", vh[i]);
229 printf("\ntask clock counters:");
230 for (i = 0; i < n; ++i)
231 printf(" %lld", vt[i]);
232 printf("\n");
233 }
234 ratio = (double)vtsum / vt0;
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000235 tst_resm(TINFO, "ratio: %.2f", ratio);
subrata_modak89823fe2009-04-02 06:48:41 +0000236 if (ratio > nhw + 0.0001) {
yaberauneya1a1b1fb2009-11-27 08:15:35 +0000237 tst_resm(TFAIL, "test failed (ratio was greater than )");
238 } else {
239 tst_resm(TINFO, "test passed");
subrata_modak89823fe2009-04-02 06:48:41 +0000240 }
Garrett Cooper49f76222010-12-19 10:22:13 -0800241 tst_exit();
242}