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