1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "alloc-util.h"
4 #include "cpu-set-util.h"
5 #include "string-util.h"
6 #include "tests.h"
7 #include "macro.h"
8 
TEST(parse_cpu_set)9 TEST(parse_cpu_set) {
10         CPUSet c = {};
11         _cleanup_free_ char *str = NULL;
12         int cpu;
13 
14         /* Single value */
15         assert_se(parse_cpu_set_full("0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
16         assert_se(c.set);
17         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
18         assert_se(CPU_ISSET_S(0, c.allocated, c.set));
19         assert_se(CPU_COUNT_S(c.allocated, c.set) == 1);
20 
21         assert_se(str = cpu_set_to_string(&c));
22         log_info("cpu_set_to_string: %s", str);
23         str = mfree(str);
24         assert_se(str = cpu_set_to_range_string(&c));
25         log_info("cpu_set_to_range_string: %s", str);
26         assert_se(streq(str, "0"));
27         str = mfree(str);
28         cpu_set_reset(&c);
29 
30         /* Simple range (from CPUAffinity example) */
31         assert_se(parse_cpu_set_full("1 2 4", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
32         assert_se(c.set);
33         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
34         assert_se(CPU_ISSET_S(1, c.allocated, c.set));
35         assert_se(CPU_ISSET_S(2, c.allocated, c.set));
36         assert_se(CPU_ISSET_S(4, c.allocated, c.set));
37         assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
38 
39         assert_se(str = cpu_set_to_string(&c));
40         log_info("cpu_set_to_string: %s", str);
41         str = mfree(str);
42         assert_se(str = cpu_set_to_range_string(&c));
43         log_info("cpu_set_to_range_string: %s", str);
44         assert_se(streq(str, "1-2 4"));
45         str = mfree(str);
46         cpu_set_reset(&c);
47 
48         /* A more interesting range */
49         assert_se(parse_cpu_set_full("0 1 2 3 8 9 10 11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
50         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
51         assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
52         for (cpu = 0; cpu < 4; cpu++)
53                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
54         for (cpu = 8; cpu < 12; cpu++)
55                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
56 
57         assert_se(str = cpu_set_to_string(&c));
58         log_info("cpu_set_to_string: %s", str);
59         str = mfree(str);
60         assert_se(str = cpu_set_to_range_string(&c));
61         log_info("cpu_set_to_range_string: %s", str);
62         assert_se(streq(str, "0-3 8-11"));
63         str = mfree(str);
64         cpu_set_reset(&c);
65 
66         /* Quoted strings */
67         assert_se(parse_cpu_set_full("8 '9' 10 \"11\"", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
68         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
69         assert_se(CPU_COUNT_S(c.allocated, c.set) == 4);
70         for (cpu = 8; cpu < 12; cpu++)
71                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
72         assert_se(str = cpu_set_to_string(&c));
73         log_info("cpu_set_to_string: %s", str);
74         str = mfree(str);
75         assert_se(str = cpu_set_to_range_string(&c));
76         log_info("cpu_set_to_range_string: %s", str);
77         assert_se(streq(str, "8-11"));
78         str = mfree(str);
79         cpu_set_reset(&c);
80 
81         /* Use commas as separators */
82         assert_se(parse_cpu_set_full("0,1,2,3 8,9,10,11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
83         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
84         assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
85         for (cpu = 0; cpu < 4; cpu++)
86                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
87         for (cpu = 8; cpu < 12; cpu++)
88                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
89         assert_se(str = cpu_set_to_string(&c));
90         log_info("cpu_set_to_string: %s", str);
91         str = mfree(str);
92         cpu_set_reset(&c);
93 
94         /* Commas with spaces (and trailing comma, space) */
95         assert_se(parse_cpu_set_full("0, 1, 2, 3, 4, 5, 6, 7, 63, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
96         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
97         assert_se(CPU_COUNT_S(c.allocated, c.set) == 9);
98         for (cpu = 0; cpu < 8; cpu++)
99                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
100 
101         assert_se(CPU_ISSET_S(63, c.allocated, c.set));
102         assert_se(str = cpu_set_to_string(&c));
103         log_info("cpu_set_to_string: %s", str);
104         str = mfree(str);
105         assert_se(str = cpu_set_to_range_string(&c));
106         log_info("cpu_set_to_range_string: %s", str);
107         assert_se(streq(str, "0-7 63"));
108         str = mfree(str);
109         cpu_set_reset(&c);
110 
111         /* Ranges */
112         assert_se(parse_cpu_set_full("0-3,8-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
113         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
114         assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
115         for (cpu = 0; cpu < 4; cpu++)
116                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
117         for (cpu = 8; cpu < 12; cpu++)
118                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
119         assert_se(str = cpu_set_to_string(&c));
120         log_info("cpu_set_to_string: %s", str);
121         str = mfree(str);
122         cpu_set_reset(&c);
123 
124         /* Ranges with trailing comma, space */
125         assert_se(parse_cpu_set_full("0-3  8-11, ", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
126         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
127         assert_se(CPU_COUNT_S(c.allocated, c.set) == 8);
128         for (cpu = 0; cpu < 4; cpu++)
129                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
130         for (cpu = 8; cpu < 12; cpu++)
131                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
132         assert_se(str = cpu_set_to_string(&c));
133         log_info("cpu_set_to_string: %s", str);
134         str = mfree(str);
135         assert_se(str = cpu_set_to_range_string(&c));
136         log_info("cpu_set_to_range_string: %s", str);
137         assert_se(streq(str, "0-3 8-11"));
138         str = mfree(str);
139         cpu_set_reset(&c);
140 
141         /* Negative range (returns empty cpu_set) */
142         assert_se(parse_cpu_set_full("3-0", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
143         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
144         assert_se(CPU_COUNT_S(c.allocated, c.set) == 0);
145         cpu_set_reset(&c);
146 
147         /* Overlapping ranges */
148         assert_se(parse_cpu_set_full("0-7 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
149         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
150         assert_se(CPU_COUNT_S(c.allocated, c.set) == 12);
151         for (cpu = 0; cpu < 12; cpu++)
152                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
153         assert_se(str = cpu_set_to_string(&c));
154         log_info("cpu_set_to_string: %s", str);
155         str = mfree(str);
156         assert_se(str = cpu_set_to_range_string(&c));
157         log_info("cpu_set_to_range_string: %s", str);
158         assert_se(streq(str, "0-11"));
159         str = mfree(str);
160         cpu_set_reset(&c);
161 
162         /* Mix ranges and individual CPUs */
163         assert_se(parse_cpu_set_full("0,2 4-11", &c, true, NULL, "fake", 1, "CPUAffinity") >= 0);
164         assert_se(c.allocated >= DIV_ROUND_UP(sizeof(__cpu_mask), 8));
165         assert_se(CPU_COUNT_S(c.allocated, c.set) == 10);
166         assert_se(CPU_ISSET_S(0, c.allocated, c.set));
167         assert_se(CPU_ISSET_S(2, c.allocated, c.set));
168         for (cpu = 4; cpu < 12; cpu++)
169                 assert_se(CPU_ISSET_S(cpu, c.allocated, c.set));
170         assert_se(str = cpu_set_to_string(&c));
171         log_info("cpu_set_to_string: %s", str);
172         str = mfree(str);
173         assert_se(str = cpu_set_to_range_string(&c));
174         log_info("cpu_set_to_range_string: %s", str);
175         assert_se(streq(str, "0 2 4-11"));
176         str = mfree(str);
177         cpu_set_reset(&c);
178 
179         /* Garbage */
180         assert_se(parse_cpu_set_full("0 1 2 3 garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
181         assert_se(!c.set);
182         assert_se(c.allocated == 0);
183 
184         /* Range with garbage */
185         assert_se(parse_cpu_set_full("0-3 8-garbage", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
186         assert_se(!c.set);
187         assert_se(c.allocated == 0);
188 
189         /* Empty string */
190         assert_se(parse_cpu_set_full("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
191         assert_se(!c.set);                /* empty string returns NULL */
192         assert_se(c.allocated == 0);
193 
194         /* Runaway quoted string */
195         assert_se(parse_cpu_set_full("0 1 2 3 \"4 5 6 7 ", &c, true, NULL, "fake", 1, "CPUAffinity") == -EINVAL);
196         assert_se(!c.set);
197         assert_se(c.allocated == 0);
198 
199         /* Maximum allocation */
200         assert_se(parse_cpu_set_full("8000-8191", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
201         assert_se(CPU_COUNT_S(c.allocated, c.set) == 192);
202         assert_se(str = cpu_set_to_string(&c));
203         log_info("cpu_set_to_string: %s", str);
204         str = mfree(str);
205         assert_se(str = cpu_set_to_range_string(&c));
206         log_info("cpu_set_to_range_string: %s", str);
207         assert_se(streq(str, "8000-8191"));
208         str = mfree(str);
209         cpu_set_reset(&c);
210 }
211 
TEST(parse_cpu_set_extend)212 TEST(parse_cpu_set_extend) {
213         CPUSet c = {};
214         _cleanup_free_ char *s1 = NULL, *s2 = NULL;
215 
216         assert_se(parse_cpu_set_extend("1 3", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
217         assert_se(CPU_COUNT_S(c.allocated, c.set) == 2);
218         assert_se(s1 = cpu_set_to_string(&c));
219         log_info("cpu_set_to_string: %s", s1);
220 
221         assert_se(parse_cpu_set_extend("4", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
222         assert_se(CPU_COUNT_S(c.allocated, c.set) == 3);
223         assert_se(s2 = cpu_set_to_string(&c));
224         log_info("cpu_set_to_string: %s", s2);
225 
226         assert_se(parse_cpu_set_extend("", &c, true, NULL, "fake", 1, "CPUAffinity") == 0);
227         assert_se(!c.set);
228         assert_se(c.allocated == 0);
229         log_info("cpu_set_to_string: (null)");
230 }
231 
TEST(cpu_set_to_from_dbus)232 TEST(cpu_set_to_from_dbus) {
233         _cleanup_(cpu_set_reset) CPUSet c = {}, c2 = {};
234         _cleanup_free_ char *s = NULL;
235 
236         assert_se(parse_cpu_set_extend("1 3 8 100-200", &c, true, NULL, "fake", 1, "CPUAffinity") == 1);
237         assert_se(s = cpu_set_to_string(&c));
238         log_info("cpu_set_to_string: %s", s);
239         assert_se(CPU_COUNT_S(c.allocated, c.set) == 104);
240 
241         _cleanup_free_ uint8_t *array = NULL;
242         size_t allocated;
243         static const char expected[32] =
244                 "\x0A\x01\x00\x00\x00\x00\x00\x00\x00\x00"
245                 "\x00\x00\xF0\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
246                 "\xFF\xFF\xFF\xFF\xFF\x01";
247 
248         assert_se(cpu_set_to_dbus(&c, &array, &allocated) == 0);
249         assert_se(array);
250         assert_se(allocated == c.allocated);
251 
252         assert_se(allocated <= sizeof expected);
253         assert_se(allocated >= DIV_ROUND_UP(201u, 8u)); /* We need at least 201 bits for our mask */
254         assert_se(memcmp(array, expected, allocated) == 0);
255 
256         assert_se(cpu_set_from_dbus(array, allocated, &c2) == 0);
257         assert_se(c2.set);
258         assert_se(c2.allocated == c.allocated);
259         assert_se(memcmp(c.set, c2.set, c.allocated) == 0);
260 }
261 
TEST(cpus_in_affinity_mask)262 TEST(cpus_in_affinity_mask) {
263         int r;
264 
265         r = cpus_in_affinity_mask();
266         assert_se(r > 0);
267         log_info("cpus_in_affinity_mask: %d", r);
268 }
269 
TEST(print_cpu_alloc_size)270 TEST(print_cpu_alloc_size) {
271         log_info("CPU_ALLOC_SIZE(1) = %zu", CPU_ALLOC_SIZE(1));
272         log_info("CPU_ALLOC_SIZE(9) = %zu", CPU_ALLOC_SIZE(9));
273         log_info("CPU_ALLOC_SIZE(64) = %zu", CPU_ALLOC_SIZE(64));
274         log_info("CPU_ALLOC_SIZE(65) = %zu", CPU_ALLOC_SIZE(65));
275         log_info("CPU_ALLOC_SIZE(1024) = %zu", CPU_ALLOC_SIZE(1024));
276         log_info("CPU_ALLOC_SIZE(1025) = %zu", CPU_ALLOC_SIZE(1025));
277         log_info("CPU_ALLOC_SIZE(8191) = %zu", CPU_ALLOC_SIZE(8191));
278 }
279 
280 DEFINE_TEST_MAIN(LOG_INFO);
281