]>
Commit | Line | Data |
---|---|---|
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); |