]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / tst-skeleton-affinity.c
CommitLineData
2359035a 1/* Generic test case for CPU affinity functions.
f7a9f785 2 Copyright (C) 2015-2016 Free Software Foundation, Inc.
2359035a
FW
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library 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 the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19/* This file is included by the tst-affinity*.c files to test the two
20 variants of the functions, under different conditions. The
21 following functions have to be definied:
22
23 static int getaffinity (size_t, cpu_set_t *);
24 static int setaffinity (size_t, const cpu_set_t *);
25 static bool early_test (struct conf *);
26
27 The first two functions shall affect the affinity mask for the
28 current thread and return 0 for success, -1 for error (with an
29 error code in errno).
30
31 early_test is invoked before the tests in this file affect the
32 affinity masks. If it returns true, testing continues, otherwise
33 no more tests run and the overall test exits with status 1.
34*/
35
36#include <errno.h>
37#include <limits.h>
38#include <sched.h>
39#include <stdbool.h>
40#include <stdio.h>
41
42/* CPU set configuration determined. Can be used from early_test. */
43struct conf
44{
45 int set_size; /* in bits */
46 int last_cpu;
47};
48
49static int
50find_set_size (void)
51{
52 /* There is considerable controversy about how to determine the size
53 of the kernel CPU mask. The probing loop below is only intended
54 for testing purposes. */
55 for (int num_cpus = 64; num_cpus <= INT_MAX / 2; ++num_cpus)
56 {
57 cpu_set_t *set = CPU_ALLOC (num_cpus);
58 size_t size = CPU_ALLOC_SIZE (num_cpus);
59
60 if (set == NULL)
61 {
62 printf ("error: CPU_ALLOC (%d) failed\n", num_cpus);
63 return -1;
64 }
65 if (getaffinity (size, set) == 0)
66 {
67 CPU_FREE (set);
68 return num_cpus;
69 }
70 if (errno != EINVAL)
71 {
72 printf ("error: getaffinity for %d CPUs: %m\n", num_cpus);
73 CPU_FREE (set);
74 return -1;
75 }
76 CPU_FREE (set);
77 }
78 puts ("error: Cannot find maximum CPU number");
79 return -1;
80}
81
82static int
83find_last_cpu (const cpu_set_t *set, size_t size)
84{
85 /* We need to determine the set size with CPU_COUNT_S and the
86 cpus_found counter because there is no direct way to obtain the
87 actual CPU set size, in bits, from the value of
88 CPU_ALLOC_SIZE. */
89 size_t cpus_found = 0;
90 size_t total_cpus = CPU_COUNT_S (size, set);
91 int last_cpu = -1;
92
93 for (int cpu = 0; cpus_found < total_cpus; ++cpu)
94 {
95 if (CPU_ISSET_S (cpu, size, set))
96 {
97 last_cpu = cpu;
98 ++cpus_found;
99 }
100 }
101 return last_cpu;
102}
103
104static void
105setup_conf (struct conf *conf)
106{
107 *conf = (struct conf) {-1, -1};
108 conf->set_size = find_set_size ();
109 if (conf->set_size > 0)
110 {
111 cpu_set_t *set = CPU_ALLOC (conf->set_size);
112
113 if (set == NULL)
114 {
115 printf ("error: CPU_ALLOC (%d) failed\n", conf->set_size);
116 CPU_FREE (set);
117 return;
118 }
119 if (getaffinity (CPU_ALLOC_SIZE (conf->set_size), set) < 0)
120 {
121 printf ("error: getaffinity failed: %m\n");
122 CPU_FREE (set);
123 return;
124 }
125 conf->last_cpu = find_last_cpu (set, CPU_ALLOC_SIZE (conf->set_size));
126 if (conf->last_cpu < 0)
127 puts ("info: No test CPU found");
128 CPU_FREE (set);
129 }
130}
131
132static bool
133test_size (const struct conf *conf, size_t size)
134{
135 if (size < conf->set_size)
136 {
137 printf ("info: Test not run for CPU set size %zu\n", size);
138 return true;
139 }
140
141 cpu_set_t *initial_set = CPU_ALLOC (size);
142 cpu_set_t *set2 = CPU_ALLOC (size);
143 cpu_set_t *active_cpu_set = CPU_ALLOC (size);
144
145 if (initial_set == NULL || set2 == NULL || active_cpu_set == NULL)
146 {
147 printf ("error: size %zu: CPU_ALLOC failed\n", size);
148 return false;
149 }
150 size_t kernel_size = CPU_ALLOC_SIZE (size);
151
152 if (getaffinity (kernel_size, initial_set) < 0)
153 {
154 printf ("error: size %zu: getaffinity: %m\n", size);
155 return false;
156 }
157 if (setaffinity (kernel_size, initial_set) < 0)
158 {
159 printf ("error: size %zu: setaffinity: %m\n", size);
160 return true;
161 }
162
163 /* Use one-CPU set to test switching between CPUs. */
164 int last_active_cpu = -1;
165 for (int cpu = 0; cpu <= conf->last_cpu; ++cpu)
166 {
167 int active_cpu = sched_getcpu ();
168 if (last_active_cpu >= 0 && last_active_cpu != active_cpu)
169 {
170 printf ("error: Unexpected CPU %d, expected %d\n",
171 active_cpu, last_active_cpu);
172 return false;
173 }
174
175 if (!CPU_ISSET_S (cpu, kernel_size, initial_set))
176 continue;
177 last_active_cpu = cpu;
178
179 CPU_ZERO_S (kernel_size, active_cpu_set);
180 CPU_SET_S (cpu, kernel_size, active_cpu_set);
181 if (setaffinity (kernel_size, active_cpu_set) < 0)
182 {
183 printf ("error: size %zu: setaffinity (%d): %m\n", size, cpu);
184 return false;
185 }
186 active_cpu = sched_getcpu ();
187 if (active_cpu != cpu)
188 {
189 printf ("error: Unexpected CPU %d, expected %d\n", active_cpu, cpu);
190 return false;
191 }
192 if (getaffinity (kernel_size, set2) < 0)
193 {
194 printf ("error: size %zu: getaffinity (2): %m\n", size);
195 return false;
196 }
197 if (!CPU_EQUAL_S (kernel_size, active_cpu_set, set2))
198 {
199 printf ("error: size %zu: CPU sets do not match\n", size);
200 return false;
201 }
202 }
203
204 /* Test setting the all-ones set. */
205 for (int cpu = 0; cpu < size; ++cpu)
206 CPU_SET_S (cpu, kernel_size, set2);
207 if (setaffinity (kernel_size, set2) < 0)
208 {
209 printf ("error: size %zu: setaffinity (3): %m\n", size);
210 return false;
211 }
212
213 if (setaffinity (kernel_size, initial_set) < 0)
214 {
215 printf ("error: size %zu: setaffinity (4): %m\n", size);
216 return false;
217 }
218 if (getaffinity (kernel_size, set2) < 0)
219 {
220 printf ("error: size %zu: getaffinity (3): %m\n", size);
221 return false;
222 }
223 if (!CPU_EQUAL_S (kernel_size, initial_set, set2))
224 {
225 printf ("error: size %zu: CPU sets do not match (2)\n", size);
226 return false;
227 }
228
229 CPU_FREE (initial_set);
230 CPU_FREE (set2);
231 CPU_FREE (active_cpu_set);
232
233 return true;
234}
235
236static int
237do_test (void)
238{
239 {
240 cpu_set_t set;
241 if (getaffinity (sizeof (set), &set) < 0 && errno == ENOSYS)
242 {
243 puts ("warning: getaffinity not supported, test cannot run");
244 return 0;
245 }
246 if (sched_getcpu () < 0 && errno == ENOSYS)
247 {
248 puts ("warning: sched_getcpu not supported, test cannot run");
249 return 0;
250 }
251 }
252
253 struct conf conf;
254 setup_conf (&conf);
255 printf ("info: Detected CPU set size (in bits): %d\n", conf.set_size);
256 printf ("info: Maximum test CPU: %d\n", conf.last_cpu);
257 if (conf.set_size < 0 || conf.last_cpu < 0)
258 return 1;
259
260 if (!early_test (&conf))
261 return 1;
262
263 bool error = false;
264 error |= !test_size (&conf, 1024);
265 error |= !test_size (&conf, conf.set_size);
266 error |= !test_size (&conf, 2);
267 error |= !test_size (&conf, 32);
268 error |= !test_size (&conf, 40);
269 error |= !test_size (&conf, 64);
270 error |= !test_size (&conf, 96);
271 error |= !test_size (&conf, 128);
272 error |= !test_size (&conf, 256);
273 error |= !test_size (&conf, 8192);
274 return error;
275}
276
277#define TEST_FUNCTION do_test ()
278#include "../test-skeleton.c"