Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / tools / testing / selftests / powerpc / pmu / lib.c
1 /*
2  * Copyright 2014, Michael Ellerman, IBM Corp.
3  * Licensed under GPLv2.
4  */
5
6 #define _GNU_SOURCE     /* For CPU_ZERO etc. */
7
8 #include <errno.h>
9 #include <sched.h>
10 #include <setjmp.h>
11 #include <stdlib.h>
12 #include <sys/wait.h>
13
14 #include "utils.h"
15 #include "lib.h"
16
17
18 int pick_online_cpu(void)
19 {
20         cpu_set_t mask;
21         int cpu;
22
23         CPU_ZERO(&mask);
24
25         if (sched_getaffinity(0, sizeof(mask), &mask)) {
26                 perror("sched_getaffinity");
27                 return -1;
28         }
29
30         /* We prefer a primary thread, but skip 0 */
31         for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
32                 if (CPU_ISSET(cpu, &mask))
33                         return cpu;
34
35         /* Search for anything, but in reverse */
36         for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
37                 if (CPU_ISSET(cpu, &mask))
38                         return cpu;
39
40         printf("No cpus in affinity mask?!\n");
41         return -1;
42 }
43
44 int bind_to_cpu(int cpu)
45 {
46         cpu_set_t mask;
47
48         printf("Binding to cpu %d\n", cpu);
49
50         CPU_ZERO(&mask);
51         CPU_SET(cpu, &mask);
52
53         return sched_setaffinity(0, sizeof(mask), &mask);
54 }
55
56 #define PARENT_TOKEN    0xAA
57 #define CHILD_TOKEN     0x55
58
59 int sync_with_child(union pipe read_pipe, union pipe write_pipe)
60 {
61         char c = PARENT_TOKEN;
62
63         FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
64         FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
65         if (c != CHILD_TOKEN) /* sometimes expected */
66                 return 1;
67
68         return 0;
69 }
70
71 int wait_for_parent(union pipe read_pipe)
72 {
73         char c;
74
75         FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
76         FAIL_IF(c != PARENT_TOKEN);
77
78         return 0;
79 }
80
81 int notify_parent(union pipe write_pipe)
82 {
83         char c = CHILD_TOKEN;
84
85         FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
86
87         return 0;
88 }
89
90 int notify_parent_of_error(union pipe write_pipe)
91 {
92         char c = ~CHILD_TOKEN;
93
94         FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
95
96         return 0;
97 }
98
99 int wait_for_child(pid_t child_pid)
100 {
101         int rc;
102
103         if (waitpid(child_pid, &rc, 0) == -1) {
104                 perror("waitpid");
105                 return 1;
106         }
107
108         if (WIFEXITED(rc))
109                 rc = WEXITSTATUS(rc);
110         else
111                 rc = 1; /* Signal or other */
112
113         return rc;
114 }
115
116 int kill_child_and_wait(pid_t child_pid)
117 {
118         kill(child_pid, SIGTERM);
119
120         return wait_for_child(child_pid);
121 }
122
123 static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
124 {
125         volatile int i = 0;
126
127         /*
128          * We are just here to eat cpu and die. So make sure we can be killed,
129          * and also don't do any custom SIGTERM handling.
130          */
131         signal(SIGTERM, SIG_DFL);
132
133         notify_parent(write_pipe);
134         wait_for_parent(read_pipe);
135
136         /* Soak up cpu forever */
137         while (1) i++;
138
139         return 0;
140 }
141
142 pid_t eat_cpu(int (test_function)(void))
143 {
144         union pipe read_pipe, write_pipe;
145         int cpu, rc;
146         pid_t pid;
147
148         cpu = pick_online_cpu();
149         FAIL_IF(cpu < 0);
150         FAIL_IF(bind_to_cpu(cpu));
151
152         if (pipe(read_pipe.fds) == -1)
153                 return -1;
154
155         if (pipe(write_pipe.fds) == -1)
156                 return -1;
157
158         pid = fork();
159         if (pid == 0)
160                 exit(eat_cpu_child(write_pipe, read_pipe));
161
162         if (sync_with_child(read_pipe, write_pipe)) {
163                 rc = -1;
164                 goto out;
165         }
166
167         printf("main test running as pid %d\n", getpid());
168
169         rc = test_function();
170 out:
171         kill(pid, SIGKILL);
172
173         return rc;
174 }
175
176 struct addr_range libc, vdso;
177
178 int parse_proc_maps(void)
179 {
180         unsigned long start, end;
181         char execute, name[128];
182         FILE *f;
183         int rc;
184
185         f = fopen("/proc/self/maps", "r");
186         if (!f) {
187                 perror("fopen");
188                 return -1;
189         }
190
191         do {
192                 /* This skips line with no executable which is what we want */
193                 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
194                             &start, &end, &execute, name);
195                 if (rc <= 0)
196                         break;
197
198                 if (execute != 'x')
199                         continue;
200
201                 if (strstr(name, "libc")) {
202                         libc.first = start;
203                         libc.last = end - 1;
204                 } else if (strstr(name, "[vdso]")) {
205                         vdso.first = start;
206                         vdso.last = end - 1;
207                 }
208         } while(1);
209
210         fclose(f);
211
212         return 0;
213 }
214
215 #define PARANOID_PATH   "/proc/sys/kernel/perf_event_paranoid"
216
217 bool require_paranoia_below(int level)
218 {
219         unsigned long current;
220         char *end, buf[16];
221         FILE *f;
222         int rc;
223
224         rc = -1;
225
226         f = fopen(PARANOID_PATH, "r");
227         if (!f) {
228                 perror("fopen");
229                 goto out;
230         }
231
232         if (!fgets(buf, sizeof(buf), f)) {
233                 printf("Couldn't read " PARANOID_PATH "?\n");
234                 goto out_close;
235         }
236
237         current = strtoul(buf, &end, 10);
238
239         if (end == buf) {
240                 printf("Couldn't parse " PARANOID_PATH "?\n");
241                 goto out_close;
242         }
243
244         if (current >= level)
245                 goto out;
246
247         rc = 0;
248 out_close:
249         fclose(f);
250 out:
251         return rc;
252 }
253