xref: /freebsd/tests/sys/kern/sched_affinity.c (revision c7a063741720ef81d4caa4613242579d12f1d605)
1 /*-
2  * Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 #include <sys/cdefs.h>
7 __FBSDID("$FreeBSD$");
8 
9 #include <sys/types.h>
10 #include <sys/stdint.h>
11 #include <sys/sysctl.h>
12 
13 #include <errno.h>
14 #include <sched.h>
15 
16 #include <atf-c.h>
17 
18 static uint32_t maxcpuid;
19 static uint32_t maxcpus;
20 static uint32_t cpus;
21 
22 static uint32_t
23 support_getcpus(void)
24 {
25 	uint32_t val;
26 	size_t sz = sizeof(val);
27 
28 	ATF_REQUIRE(sysctlbyname("kern.smp.cpus", &val, &sz, NULL, 0) == 0);
29 	return (val);
30 }
31 
32 static uint32_t
33 support_getmaxcpus(void)
34 {
35 	uint32_t val;
36 	size_t sz = sizeof(val);
37 
38 	ATF_REQUIRE(sysctlbyname("kern.smp.maxcpus", &val, &sz, NULL, 0) == 0);
39 	return (val);
40 }
41 
42 static uint32_t
43 support_getmaxcpuid(void)
44 {
45 	cpuset_t *set;
46 	int setsize, rv;
47 	uint32_t i, id;
48 
49 	for (i = 1; i < maxcpus; i++) {
50 		setsize = CPU_ALLOC_SIZE(i);
51 		set = CPU_ALLOC(i);
52 		ATF_REQUIRE(set != NULL);
53 		CPU_ZERO_S(i, set);
54 		rv = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
55 		    -1, setsize, set);
56 		if (rv == 0) {
57 			id = __BIT_FLS(i, set) - 1;
58 			CPU_FREE(set);
59 			break;
60 		}
61 		CPU_FREE(set);
62 	}
63 	ATF_REQUIRE(rv == 0);
64 	return (id);
65 }
66 
67 ATF_TC_WITHOUT_HEAD(test_setinvalidcpu);
68 ATF_TC_BODY(test_setinvalidcpu, tc)
69 {
70 	size_t cpusetsize;
71 	cpuset_t *set;
72 
73 	cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
74 	set = CPU_ALLOC(maxcpuid + 1);
75 	ATF_REQUIRE(set != NULL);
76 	CPU_ZERO_S(maxcpuid + 1, set);
77 	CPU_SET_S(maxcpuid + 1, maxcpuid + 1, set);
78 	CPU_SET_S(maxcpuid - 1, maxcpuid + 1, set);
79 	ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == 0);
80 	CPU_FREE(set);
81 
82 	cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1);
83 	set = CPU_ALLOC(maxcpus + 1);
84 	ATF_REQUIRE(set != NULL);
85 	CPU_ZERO_S(maxcpus + 1, set);
86 	CPU_SET_S(maxcpuid + 1, maxcpus + 1, set);
87 	CPU_SET_S(maxcpuid - 1, maxcpus + 1, set);
88 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
89 	    -1, cpusetsize, set) == -1);
90 	ATF_REQUIRE_EQ(errno, EINVAL);
91 	CPU_FREE(set);
92 }
93 
94 ATF_TC_WITHOUT_HEAD(test_setvalidcpu);
95 ATF_TC_BODY(test_setvalidcpu, tc)
96 {
97 	size_t cpusetsize;
98 	cpuset_t *set;
99 	int cpu;
100 
101 	ATF_REQUIRE(maxcpuid < maxcpus);
102 	cpu = maxcpuid > 1 ? maxcpuid - 1 : 0;
103 
104 	cpusetsize = CPU_ALLOC_SIZE(maxcpus + 1);
105 	set = CPU_ALLOC(maxcpus + 1);
106 	ATF_REQUIRE(set != NULL);
107 	CPU_ZERO_S(maxcpus + 1, set);
108 	CPU_SET_S(cpu, maxcpus + 1, set);
109 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
110 	    -1, cpusetsize, set) == 0);
111 	ATF_REQUIRE_EQ(cpu, sched_getcpu());
112 	CPU_FREE(set);
113 }
114 
115 ATF_TC_WITHOUT_HEAD(test_setzeroset1);
116 ATF_TC_BODY(test_setzeroset1, tc)
117 {
118 	size_t cpusetsize;
119 	cpuset_t *set;
120 
121 	cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
122 	set = CPU_ALLOC(maxcpuid + 1);
123 	ATF_REQUIRE(set != NULL);
124 	CPU_ZERO_S(maxcpuid + 1, set);
125 	ATF_REQUIRE(sched_setaffinity(0, cpusetsize, set) == -1);
126 	ATF_REQUIRE_EQ(errno, EINVAL);
127 	CPU_FREE(set);
128 }
129 
130 ATF_TC_WITHOUT_HEAD(test_setzeroset2);
131 ATF_TC_BODY(test_setzeroset2, tc)
132 {
133 	size_t cpusetsize;
134 	cpuset_t *set;
135 
136 	cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
137 	set = CPU_ALLOC(maxcpuid + 1);
138 	ATF_REQUIRE(set != NULL);
139 	CPU_ZERO_S(maxcpuid + 1, set);
140 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
141 	    -1, cpusetsize, set) == -1);
142 	ATF_REQUIRE_EQ(errno, EDEADLK);
143 	CPU_FREE(set);
144 }
145 
146 ATF_TC_WITHOUT_HEAD(test_setmaxsetsize);
147 ATF_TC_BODY(test_setmaxsetsize, tc)
148 {
149 	size_t cpusetsize;
150 	cpuset_t *set;
151 
152 	cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2);
153 	set = CPU_ALLOC(maxcpus * 2);
154 	ATF_REQUIRE(set != NULL);
155 	CPU_ZERO_S(maxcpus * 2, set);
156 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0);
157 	CPU_SET_S(0, maxcpus * 2, set);
158 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1);
159 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
160 	    -1, cpusetsize, set) == 0);
161 
162 	CPU_ZERO_S(maxcpus * 2, set);
163 	CPU_SET_S(maxcpuid, maxcpus * 2, set);
164 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
165 	    -1, cpusetsize, set) == 0);
166 
167 	CPU_ZERO_S(maxcpus * 2, set);
168 	CPU_SET_S(maxcpuid + 1, maxcpus * 2, set);
169 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
170 	    -1, cpusetsize, set) == -1);
171 	ATF_REQUIRE_EQ(errno, EINVAL);
172 	CPU_FREE(set);
173 }
174 
175 ATF_TC_WITHOUT_HEAD(test_setminsetsize);
176 ATF_TC_BODY(test_setminsetsize, tc)
177 {
178 	size_t cpusetsize = 1;
179 	int8_t set;
180 
181 	if (cpus <= 8)
182 		return;
183 
184 	set = 1;
185 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
186 	    -1, cpusetsize, (const cpuset_t *)&set) == 0);
187 	set = 0;
188 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
189 	    -1, cpusetsize, (const cpuset_t *)&set) == -1);
190 	ATF_REQUIRE_EQ(errno, EDEADLK);
191 }
192 
193 ATF_TC_WITHOUT_HEAD(test_getminsetsize);
194 ATF_TC_BODY(test_getminsetsize, tc)
195 {
196 	size_t cpusetsize = 1;
197 	int8_t set = 0;
198 
199 	if (cpus < 9)
200 		return;
201 	ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
202 	    -1, cpusetsize, (cpuset_t *)&set) == -1);
203 	ATF_REQUIRE_EQ(errno, ERANGE);
204 }
205 
206 ATF_TC_WITHOUT_HEAD(test_getsetsize);
207 ATF_TC_BODY(test_getsetsize, tc)
208 {
209 	size_t cpusetsize;
210 	cpuset_t *set;
211 
212 	cpusetsize = CPU_ALLOC_SIZE(maxcpuid + 1);
213 	set = CPU_ALLOC(maxcpuid + 1);
214 	ATF_REQUIRE(set != NULL);
215 	CPU_ZERO_S(maxcpuid + 1, set);
216 	ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
217 	    -1, cpusetsize, set) == 0);
218 	CPU_FREE(set);
219 }
220 
221 ATF_TC_WITHOUT_HEAD(test_holes);
222 ATF_TC_BODY(test_holes, tc)
223 {
224 	cpuset_t *set;
225 	int cpusetsize;
226 
227 	cpusetsize = CPU_ALLOC_SIZE(maxcpus * 2);
228 	set = CPU_ALLOC(maxcpus * 2);
229 	ATF_REQUIRE(set != NULL);
230 	CPU_ZERO_S(maxcpus * 2, set);
231 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0);
232 	CPU_SET_S(maxcpuid, maxcpus * 2, set);
233 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1);
234 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
235 	    -1, cpusetsize, set) == 0);
236 
237 	CPU_ZERO_S(maxcpus * 2, set);
238 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 0);
239 	CPU_SET_S(maxcpuid + 1, maxcpus * 2, set);
240 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1);
241 	ATF_REQUIRE(cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
242 	    -1, cpusetsize, set) == -1);
243 	ATF_REQUIRE_EQ(errno, EINVAL);
244 
245 	ATF_REQUIRE(CPU_COUNT_S(maxcpus * 2, set) == 1);
246 	ATF_REQUIRE(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
247 	    -1, cpusetsize, set) == 0);
248 	ATF_REQUIRE(CPU_ISSET_S(maxcpuid + 1, maxcpus * 2, set) == false);
249 	ATF_REQUIRE(CPU_ISSET_S(maxcpuid, maxcpus * 2, set) == true);
250 	ATF_REQUIRE_EQ(maxcpuid, (uint32_t)sched_getcpu());
251 }
252 
253 ATF_TP_ADD_TCS(tp)
254 {
255 
256 	cpus = support_getcpus();
257 	maxcpus = support_getmaxcpus();
258 	maxcpuid = support_getmaxcpuid();
259 
260 	ATF_TP_ADD_TC(tp, test_setinvalidcpu);
261 	ATF_TP_ADD_TC(tp, test_setvalidcpu);
262 	ATF_TP_ADD_TC(tp, test_setzeroset1);
263 	ATF_TP_ADD_TC(tp, test_setzeroset2);
264 
265 	ATF_TP_ADD_TC(tp, test_setminsetsize);
266 	ATF_TP_ADD_TC(tp, test_setmaxsetsize);
267 
268 	ATF_TP_ADD_TC(tp, test_getminsetsize);
269 	ATF_TP_ADD_TC(tp, test_getsetsize);
270 
271 	ATF_TP_ADD_TC(tp, test_holes);
272 
273 	return (atf_no_error());
274 }
275