1 /* Generic test case for CPU affinity functions.
2 Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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 <https://www.gnu.org/licenses/>. */
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 defined:
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 *);
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
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.
42 /* CPU set configuration determined. Can be used from early_test. */
45 int set_size
; /* in bits */
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
)
57 cpu_set_t
*set
= CPU_ALLOC (num_cpus
);
58 size_t size
= CPU_ALLOC_SIZE (num_cpus
);
62 printf ("error: CPU_ALLOC (%d) failed\n", num_cpus
);
65 if (getaffinity (size
, set
) == 0)
72 printf ("error: getaffinity for %d CPUs: %m\n", num_cpus
);
78 puts ("error: Cannot find maximum CPU number");
83 find_last_cpu (const cpu_set_t
*set
, size_t size
)
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
89 size_t cpus_found
= 0;
90 size_t total_cpus
= CPU_COUNT_S (size
, set
);
93 for (int cpu
= 0; cpus_found
< total_cpus
; ++cpu
)
95 if (CPU_ISSET_S (cpu
, size
, set
))
105 setup_conf (struct conf
*conf
)
107 *conf
= (struct conf
) {-1, -1};
108 conf
->set_size
= find_set_size ();
109 if (conf
->set_size
> 0)
111 cpu_set_t
*set
= CPU_ALLOC (conf
->set_size
);
115 printf ("error: CPU_ALLOC (%d) failed\n", conf
->set_size
);
119 if (getaffinity (CPU_ALLOC_SIZE (conf
->set_size
), set
) < 0)
121 printf ("error: getaffinity failed: %m\n");
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");
133 test_size (const struct conf
*conf
, size_t size
)
135 if (size
< conf
->set_size
)
137 printf ("info: Test not run for CPU set size %zu\n", size
);
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
);
145 if (initial_set
== NULL
|| set2
== NULL
|| active_cpu_set
== NULL
)
147 printf ("error: size %zu: CPU_ALLOC failed\n", size
);
150 size_t kernel_size
= CPU_ALLOC_SIZE (size
);
152 if (getaffinity (kernel_size
, initial_set
) < 0)
154 printf ("error: size %zu: getaffinity: %m\n", size
);
157 if (setaffinity (kernel_size
, initial_set
) < 0)
159 printf ("error: size %zu: setaffinity: %m\n", size
);
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
)
167 int active_cpu
= sched_getcpu ();
168 if (last_active_cpu
>= 0 && last_active_cpu
!= active_cpu
)
170 printf ("error: Unexpected CPU %d, expected %d\n",
171 active_cpu
, last_active_cpu
);
175 if (!CPU_ISSET_S (cpu
, kernel_size
, initial_set
))
177 last_active_cpu
= cpu
;
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)
183 printf ("error: size %zu: setaffinity (%d): %m\n", size
, cpu
);
186 active_cpu
= sched_getcpu ();
187 if (active_cpu
!= cpu
)
189 printf ("error: Unexpected CPU %d, expected %d\n", active_cpu
, cpu
);
192 unsigned int numa_cpu
, numa_node
;
193 if (getcpu (&numa_cpu
, &numa_node
) != 0)
195 printf ("error: getcpu: %m\n");
198 if ((unsigned int) active_cpu
!= numa_cpu
)
200 printf ("error: Unexpected CPU %d, expected %d\n",
201 active_cpu
, numa_cpu
);
204 if (getaffinity (kernel_size
, set2
) < 0)
206 printf ("error: size %zu: getaffinity (2): %m\n", size
);
209 if (!CPU_EQUAL_S (kernel_size
, active_cpu_set
, set2
))
211 printf ("error: size %zu: CPU sets do not match\n", size
);
216 /* Test setting the all-ones set. */
217 for (int cpu
= 0; cpu
< size
; ++cpu
)
218 CPU_SET_S (cpu
, kernel_size
, set2
);
219 if (setaffinity (kernel_size
, set2
) < 0)
221 printf ("error: size %zu: setaffinity (3): %m\n", size
);
225 if (setaffinity (kernel_size
, initial_set
) < 0)
227 printf ("error: size %zu: setaffinity (4): %m\n", size
);
230 if (getaffinity (kernel_size
, set2
) < 0)
232 printf ("error: size %zu: getaffinity (3): %m\n", size
);
235 if (!CPU_EQUAL_S (kernel_size
, initial_set
, set2
))
237 printf ("error: size %zu: CPU sets do not match (2)\n", size
);
241 CPU_FREE (initial_set
);
243 CPU_FREE (active_cpu_set
);
253 if (getaffinity (sizeof (set
), &set
) < 0 && errno
== ENOSYS
)
255 puts ("warning: getaffinity not supported, test cannot run");
258 if (sched_getcpu () < 0 && errno
== ENOSYS
)
260 puts ("warning: sched_getcpu not supported, test cannot run");
267 /* Note: The CPU set size in bits can be less than the CPU count
268 (and the maximum test CPU) because the userspace interface rounds
269 up the bit count, and the rounded-up buffer size is passed into
270 the kernel. The kernel does not know that some of the buffer are
271 actually padding, and writes data there. */
272 printf ("info: Detected CPU set size (in bits): %d\n", conf
.set_size
);
273 printf ("info: Maximum test CPU: %d\n", conf
.last_cpu
);
274 if (conf
.set_size
< 0 || conf
.last_cpu
< 0)
277 if (!early_test (&conf
))
281 error
|= !test_size (&conf
, 1024);
282 error
|= !test_size (&conf
, conf
.set_size
);
283 error
|= !test_size (&conf
, 2);
284 error
|= !test_size (&conf
, 32);
285 error
|= !test_size (&conf
, 40);
286 error
|= !test_size (&conf
, 64);
287 error
|= !test_size (&conf
, 96);
288 error
|= !test_size (&conf
, 128);
289 error
|= !test_size (&conf
, 256);
290 error
|= !test_size (&conf
, 8192);
294 #define TEST_FUNCTION do_test ()
295 #include "../test-skeleton.c"