1 /* 2 * SMP parsing unit-tests 3 * 4 * Copyright (c) 2021 Huawei Technologies Co., Ltd 5 * 6 * Authors: 7 * Yanan Wang <wangyanan55@huawei.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 10 * See the COPYING.LIB file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qom/object.h" 15 #include "qemu/module.h" 16 #include "qapi/error.h" 17 18 #include "hw/boards.h" 19 20 #define T true 21 #define F false 22 23 #define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */ 24 #define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */ 25 26 #define SMP_MACHINE_NAME "TEST-SMP" 27 28 /* 29 * Used to define the generic 3-level CPU topology hierarchy 30 * -sockets/cores/threads 31 */ 32 #define SMP_CONFIG_GENERIC(ha, a, hb, b, hc, c, hd, d, he, e) \ 33 { \ 34 .has_cpus = ha, .cpus = a, \ 35 .has_sockets = hb, .sockets = b, \ 36 .has_cores = hc, .cores = c, \ 37 .has_threads = hd, .threads = d, \ 38 .has_maxcpus = he, .maxcpus = e, \ 39 } 40 41 #define CPU_TOPOLOGY_GENERIC(a, b, c, d, e) \ 42 { \ 43 .cpus = a, \ 44 .sockets = b, \ 45 .cores = c, \ 46 .threads = d, \ 47 .max_cpus = e, \ 48 } 49 50 /* 51 * Currently a 4-level topology hierarchy is supported on PC machines 52 * -sockets/dies/cores/threads 53 */ 54 #define SMP_CONFIG_WITH_DIES(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ 55 { \ 56 .has_cpus = ha, .cpus = a, \ 57 .has_sockets = hb, .sockets = b, \ 58 .has_dies = hc, .dies = c, \ 59 .has_cores = hd, .cores = d, \ 60 .has_threads = he, .threads = e, \ 61 .has_maxcpus = hf, .maxcpus = f, \ 62 } 63 64 /* 65 * Currently a 4-level topology hierarchy is supported on ARM virt machines 66 * -sockets/clusters/cores/threads 67 */ 68 #define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ 69 { \ 70 .has_cpus = ha, .cpus = a, \ 71 .has_sockets = hb, .sockets = b, \ 72 .has_clusters = hc, .clusters = c, \ 73 .has_cores = hd, .cores = d, \ 74 .has_threads = he, .threads = e, \ 75 .has_maxcpus = hf, .maxcpus = f, \ 76 } 77 78 /** 79 * @config - the given SMP configuration 80 * @expect_prefer_sockets - the expected parsing result for the 81 * valid configuration, when sockets are preferred over cores 82 * @expect_prefer_cores - the expected parsing result for the 83 * valid configuration, when cores are preferred over sockets 84 * @expect_error - the expected error report when the given 85 * configuration is invalid 86 */ 87 typedef struct SMPTestData { 88 SMPConfiguration config; 89 CpuTopology expect_prefer_sockets; 90 CpuTopology expect_prefer_cores; 91 const char *expect_error; 92 } SMPTestData; 93 94 /* 95 * List all the possible valid sub-collections of the generic 5 96 * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads), 97 * then test the automatic calculation algorithm of the missing 98 * values in the parser. 99 */ 100 static const struct SMPTestData data_generic_valid[] = { 101 { 102 /* config: no configuration provided 103 * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */ 104 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0), 105 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), 106 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), 107 }, { 108 /* config: -smp 8 109 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8 110 * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */ 111 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0), 112 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8), 113 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8), 114 }, { 115 /* config: -smp sockets=2 116 * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */ 117 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0), 118 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), 119 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), 120 }, { 121 /* config: -smp cores=4 122 * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */ 123 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0), 124 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), 125 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), 126 }, { 127 /* config: -smp threads=2 128 * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */ 129 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0), 130 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), 131 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), 132 }, { 133 /* config: -smp maxcpus=16 134 * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16 135 * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */ 136 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16), 137 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16), 138 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16), 139 }, { 140 /* config: -smp 8,sockets=2 141 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 142 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0), 143 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 144 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 145 }, { 146 /* config: -smp 8,cores=4 147 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 148 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0), 149 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 150 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 151 }, { 152 /* config: -smp 8,threads=2 153 * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8 154 * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 155 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0), 156 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8), 157 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 158 }, { 159 /* config: -smp 8,maxcpus=16 160 * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16 161 * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */ 162 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16), 163 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16), 164 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16), 165 }, { 166 /* config: -smp sockets=2,cores=4 167 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 168 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0), 169 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 170 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 171 }, { 172 /* config: -smp sockets=2,threads=2 173 * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */ 174 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0), 175 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), 176 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), 177 }, { 178 /* config: -smp sockets=2,maxcpus=16 179 * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */ 180 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16), 181 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), 182 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), 183 }, { 184 /* config: -smp cores=4,threads=2 185 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 186 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0), 187 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 188 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 189 }, { 190 /* config: -smp cores=4,maxcpus=16 191 * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */ 192 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16), 193 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), 194 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), 195 }, { 196 /* config: -smp threads=2,maxcpus=16 197 * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16 198 * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */ 199 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16), 200 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16), 201 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16), 202 }, { 203 /* config: -smp 8,sockets=2,cores=4 204 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 205 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0), 206 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 207 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 208 }, { 209 /* config: -smp 8,sockets=2,threads=2 210 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */ 211 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0), 212 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 213 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 214 }, { 215 /* config: -smp 8,sockets=2,maxcpus=16 216 * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */ 217 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16), 218 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), 219 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), 220 }, { 221 /* config: -smp 8,cores=4,threads=2 222 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 223 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0), 224 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 225 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 226 }, { 227 /* config: -smp 8,cores=4,maxcpus=16 228 * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */ 229 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16), 230 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), 231 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), 232 }, { 233 /* config: -smp 8,threads=2,maxcpus=16 234 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16 235 * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */ 236 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16), 237 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16), 238 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16), 239 }, { 240 /* config: -smp sockets=2,cores=4,threads=2 241 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 242 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0), 243 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 244 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 245 }, { 246 /* config: -smp sockets=2,cores=4,maxcpus=16 247 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 248 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16), 249 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 250 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 251 }, { 252 /* config: -smp sockets=2,threads=2,maxcpus=16 253 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 254 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16), 255 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 256 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 257 }, { 258 /* config: -smp cores=4,threads=2,maxcpus=16 259 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 260 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16), 261 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 262 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 263 }, { 264 /* config: -smp 8,sockets=2,cores=4,threads=1 265 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 266 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0), 267 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 268 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 269 }, { 270 /* config: -smp 8,sockets=2,cores=4,maxcpus=16 271 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 272 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16), 273 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 274 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 275 }, { 276 /* config: -smp 8,sockets=2,threads=2,maxcpus=16 277 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 278 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16), 279 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 280 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 281 }, { 282 /* config: -smp 8,cores=4,threads=2,maxcpus=16 283 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 284 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16), 285 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 286 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 287 }, { 288 /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16 289 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 290 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16), 291 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 292 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 293 }, { 294 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16 295 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 296 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16), 297 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 298 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 299 }, 300 }; 301 302 static const struct SMPTestData data_generic_invalid[] = { 303 { 304 /* config: -smp 2,dies=2 */ 305 .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), 306 .expect_error = "dies not supported by this machine's CPU topology", 307 }, { 308 /* config: -smp 2,clusters=2 */ 309 .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), 310 .expect_error = "clusters not supported by this machine's CPU topology", 311 }, { 312 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */ 313 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), 314 .expect_error = "Invalid CPU topology: " 315 "product of the hierarchy must match maxcpus: " 316 "sockets (2) * cores (4) * threads (2) " 317 "!= maxcpus (8)", 318 }, { 319 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */ 320 .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16), 321 .expect_error = "Invalid CPU topology: " 322 "maxcpus must be equal to or greater than smp: " 323 "sockets (2) * cores (4) * threads (2) " 324 "== maxcpus (16) < smp_cpus (18)", 325 }, { 326 /* config: -smp 1 327 * should tweak the supported min CPUs to 2 for testing */ 328 .config = SMP_CONFIG_GENERIC(T, 1, F, 0, F, 0, F, 0, F, 0), 329 .expect_error = "Invalid SMP CPUs 1. The min CPUs supported " 330 "by machine '" SMP_MACHINE_NAME "' is 2", 331 }, { 332 /* config: -smp 512 333 * should tweak the supported max CPUs to 511 for testing */ 334 .config = SMP_CONFIG_GENERIC(T, 512, F, 0, F, 0, F, 0, F, 0), 335 .expect_error = "Invalid SMP CPUs 512. The max CPUs supported " 336 "by machine '" SMP_MACHINE_NAME "' is 511", 337 }, 338 }; 339 340 static const struct SMPTestData data_with_dies_invalid[] = { 341 { 342 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */ 343 .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), 344 .expect_error = "Invalid CPU topology: " 345 "product of the hierarchy must match maxcpus: " 346 "sockets (2) * dies (2) * cores (4) * threads (2) " 347 "!= maxcpus (16)", 348 }, { 349 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */ 350 .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), 351 .expect_error = "Invalid CPU topology: " 352 "maxcpus must be equal to or greater than smp: " 353 "sockets (2) * dies (2) * cores (4) * threads (2) " 354 "== maxcpus (32) < smp_cpus (34)", 355 }, 356 }; 357 358 static const struct SMPTestData data_with_clusters_invalid[] = { 359 { 360 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */ 361 .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), 362 .expect_error = "Invalid CPU topology: " 363 "product of the hierarchy must match maxcpus: " 364 "sockets (2) * clusters (2) * cores (4) * threads (2) " 365 "!= maxcpus (16)", 366 }, { 367 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */ 368 .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), 369 .expect_error = "Invalid CPU topology: " 370 "maxcpus must be equal to or greater than smp: " 371 "sockets (2) * clusters (2) * cores (4) * threads (2) " 372 "== maxcpus (32) < smp_cpus (34)", 373 }, 374 }; 375 376 static char *smp_config_to_string(const SMPConfiguration *config) 377 { 378 return g_strdup_printf( 379 "(SMPConfiguration) {\n" 380 " .has_cpus = %5s, cpus = %" PRId64 ",\n" 381 " .has_sockets = %5s, sockets = %" PRId64 ",\n" 382 " .has_dies = %5s, dies = %" PRId64 ",\n" 383 " .has_clusters = %5s, clusters = %" PRId64 ",\n" 384 " .has_cores = %5s, cores = %" PRId64 ",\n" 385 " .has_threads = %5s, threads = %" PRId64 ",\n" 386 " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" 387 "}", 388 config->has_cpus ? "true" : "false", config->cpus, 389 config->has_sockets ? "true" : "false", config->sockets, 390 config->has_dies ? "true" : "false", config->dies, 391 config->has_clusters ? "true" : "false", config->clusters, 392 config->has_cores ? "true" : "false", config->cores, 393 config->has_threads ? "true" : "false", config->threads, 394 config->has_maxcpus ? "true" : "false", config->maxcpus); 395 } 396 397 static char *cpu_topology_to_string(const CpuTopology *topo) 398 { 399 return g_strdup_printf( 400 "(CpuTopology) {\n" 401 " .cpus = %u,\n" 402 " .sockets = %u,\n" 403 " .dies = %u,\n" 404 " .clusters = %u,\n" 405 " .cores = %u,\n" 406 " .threads = %u,\n" 407 " .max_cpus = %u,\n" 408 "}", 409 topo->cpus, topo->sockets, topo->dies, topo->clusters, 410 topo->cores, topo->threads, topo->max_cpus); 411 } 412 413 static void check_parse(MachineState *ms, const SMPConfiguration *config, 414 const CpuTopology *expect_topo, const char *expect_err, 415 bool is_valid) 416 { 417 g_autofree char *config_str = smp_config_to_string(config); 418 g_autofree char *expect_topo_str = cpu_topology_to_string(expect_topo); 419 g_autofree char *output_topo_str = NULL; 420 Error *err = NULL; 421 422 /* call the generic parser */ 423 machine_parse_smp_config(ms, config, &err); 424 425 output_topo_str = cpu_topology_to_string(&ms->smp); 426 427 /* when the configuration is supposed to be valid */ 428 if (is_valid) { 429 if ((err == NULL) && 430 (ms->smp.cpus == expect_topo->cpus) && 431 (ms->smp.sockets == expect_topo->sockets) && 432 (ms->smp.dies == expect_topo->dies) && 433 (ms->smp.clusters == expect_topo->clusters) && 434 (ms->smp.cores == expect_topo->cores) && 435 (ms->smp.threads == expect_topo->threads) && 436 (ms->smp.max_cpus == expect_topo->max_cpus)) { 437 return; 438 } 439 440 if (err != NULL) { 441 g_printerr("Test smp_parse failed!\n" 442 "Input configuration: %s\n" 443 "Should be valid: yes\n" 444 "Expected topology: %s\n\n" 445 "Result is valid: no\n" 446 "Output error report: %s\n", 447 config_str, expect_topo_str, error_get_pretty(err)); 448 goto end; 449 } 450 451 g_printerr("Test smp_parse failed!\n" 452 "Input configuration: %s\n" 453 "Should be valid: yes\n" 454 "Expected topology: %s\n\n" 455 "Result is valid: yes\n" 456 "Output topology: %s\n", 457 config_str, expect_topo_str, output_topo_str); 458 goto end; 459 } 460 461 /* when the configuration is supposed to be invalid */ 462 if (err != NULL) { 463 if (expect_err == NULL || 464 g_str_equal(expect_err, error_get_pretty(err))) { 465 error_free(err); 466 return; 467 } 468 469 g_printerr("Test smp_parse failed!\n" 470 "Input configuration: %s\n" 471 "Should be valid: no\n" 472 "Expected error report: %s\n\n" 473 "Result is valid: no\n" 474 "Output error report: %s\n", 475 config_str, expect_err, error_get_pretty(err)); 476 goto end; 477 } 478 479 g_printerr("Test smp_parse failed!\n" 480 "Input configuration: %s\n" 481 "Should be valid: no\n" 482 "Expected error report: %s\n\n" 483 "Result is valid: yes\n" 484 "Output topology: %s\n", 485 config_str, expect_err, output_topo_str); 486 487 end: 488 if (err != NULL) { 489 error_free(err); 490 } 491 492 abort(); 493 } 494 495 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) 496 { 497 MachineClass *mc = MACHINE_GET_CLASS(ms); 498 499 mc->smp_props.prefer_sockets = true; 500 check_parse(ms, &data->config, &data->expect_prefer_sockets, 501 data->expect_error, is_valid); 502 503 mc->smp_props.prefer_sockets = false; 504 check_parse(ms, &data->config, &data->expect_prefer_cores, 505 data->expect_error, is_valid); 506 } 507 508 /* The parsed results of the unsupported parameters should be 1 */ 509 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) 510 { 511 if (!mc->smp_props.dies_supported) { 512 data->expect_prefer_sockets.dies = 1; 513 data->expect_prefer_cores.dies = 1; 514 } 515 516 if (!mc->smp_props.clusters_supported) { 517 data->expect_prefer_sockets.clusters = 1; 518 data->expect_prefer_cores.clusters = 1; 519 } 520 } 521 522 static void machine_base_class_init(ObjectClass *oc, void *data) 523 { 524 MachineClass *mc = MACHINE_CLASS(oc); 525 526 mc->min_cpus = MIN_CPUS; 527 mc->max_cpus = MAX_CPUS; 528 529 mc->name = g_strdup(SMP_MACHINE_NAME); 530 } 531 532 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) 533 { 534 MachineClass *mc = MACHINE_CLASS(oc); 535 536 /* Force invalid min CPUs and max CPUs */ 537 mc->min_cpus = 2; 538 mc->max_cpus = 511; 539 } 540 541 static void machine_with_dies_class_init(ObjectClass *oc, void *data) 542 { 543 MachineClass *mc = MACHINE_CLASS(oc); 544 545 mc->smp_props.dies_supported = true; 546 } 547 548 static void machine_with_clusters_class_init(ObjectClass *oc, void *data) 549 { 550 MachineClass *mc = MACHINE_CLASS(oc); 551 552 mc->smp_props.clusters_supported = true; 553 } 554 555 static void test_generic_valid(const void *opaque) 556 { 557 const char *machine_type = opaque; 558 Object *obj = object_new(machine_type); 559 MachineState *ms = MACHINE(obj); 560 MachineClass *mc = MACHINE_GET_CLASS(obj); 561 SMPTestData data = {}; 562 int i; 563 564 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 565 data = data_generic_valid[i]; 566 unsupported_params_init(mc, &data); 567 568 smp_parse_test(ms, &data, true); 569 570 /* Unsupported parameters can be provided with their values as 1 */ 571 data.config.has_dies = true; 572 data.config.dies = 1; 573 smp_parse_test(ms, &data, true); 574 } 575 576 object_unref(obj); 577 } 578 579 static void test_generic_invalid(const void *opaque) 580 { 581 const char *machine_type = opaque; 582 Object *obj = object_new(machine_type); 583 MachineState *ms = MACHINE(obj); 584 MachineClass *mc = MACHINE_GET_CLASS(obj); 585 SMPTestData data = {}; 586 int i; 587 588 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { 589 data = data_generic_invalid[i]; 590 unsupported_params_init(mc, &data); 591 592 smp_parse_test(ms, &data, false); 593 } 594 595 object_unref(obj); 596 } 597 598 static void test_with_dies(const void *opaque) 599 { 600 const char *machine_type = opaque; 601 Object *obj = object_new(machine_type); 602 MachineState *ms = MACHINE(obj); 603 MachineClass *mc = MACHINE_GET_CLASS(obj); 604 SMPTestData data = {}; 605 unsigned int num_dies = 2; 606 int i; 607 608 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 609 data = data_generic_valid[i]; 610 unsupported_params_init(mc, &data); 611 612 /* when dies parameter is omitted, it will be set as 1 */ 613 data.expect_prefer_sockets.dies = 1; 614 data.expect_prefer_cores.dies = 1; 615 616 smp_parse_test(ms, &data, true); 617 618 /* when dies parameter is specified */ 619 data.config.has_dies = true; 620 data.config.dies = num_dies; 621 if (data.config.has_cpus) { 622 data.config.cpus *= num_dies; 623 } 624 if (data.config.has_maxcpus) { 625 data.config.maxcpus *= num_dies; 626 } 627 628 data.expect_prefer_sockets.dies = num_dies; 629 data.expect_prefer_sockets.cpus *= num_dies; 630 data.expect_prefer_sockets.max_cpus *= num_dies; 631 data.expect_prefer_cores.dies = num_dies; 632 data.expect_prefer_cores.cpus *= num_dies; 633 data.expect_prefer_cores.max_cpus *= num_dies; 634 635 smp_parse_test(ms, &data, true); 636 } 637 638 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { 639 data = data_with_dies_invalid[i]; 640 unsupported_params_init(mc, &data); 641 642 smp_parse_test(ms, &data, false); 643 } 644 645 object_unref(obj); 646 } 647 648 static void test_with_clusters(const void *opaque) 649 { 650 const char *machine_type = opaque; 651 Object *obj = object_new(machine_type); 652 MachineState *ms = MACHINE(obj); 653 MachineClass *mc = MACHINE_GET_CLASS(obj); 654 SMPTestData data = {}; 655 unsigned int num_clusters = 2; 656 int i; 657 658 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 659 data = data_generic_valid[i]; 660 unsupported_params_init(mc, &data); 661 662 /* when clusters parameter is omitted, it will be set as 1 */ 663 data.expect_prefer_sockets.clusters = 1; 664 data.expect_prefer_cores.clusters = 1; 665 666 smp_parse_test(ms, &data, true); 667 668 /* when clusters parameter is specified */ 669 data.config.has_clusters = true; 670 data.config.clusters = num_clusters; 671 if (data.config.has_cpus) { 672 data.config.cpus *= num_clusters; 673 } 674 if (data.config.has_maxcpus) { 675 data.config.maxcpus *= num_clusters; 676 } 677 678 data.expect_prefer_sockets.clusters = num_clusters; 679 data.expect_prefer_sockets.cpus *= num_clusters; 680 data.expect_prefer_sockets.max_cpus *= num_clusters; 681 data.expect_prefer_cores.clusters = num_clusters; 682 data.expect_prefer_cores.cpus *= num_clusters; 683 data.expect_prefer_cores.max_cpus *= num_clusters; 684 685 smp_parse_test(ms, &data, true); 686 } 687 688 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) { 689 data = data_with_clusters_invalid[i]; 690 unsupported_params_init(mc, &data); 691 692 smp_parse_test(ms, &data, false); 693 } 694 695 object_unref(obj); 696 } 697 698 /* Type info of the tested machine */ 699 static const TypeInfo smp_machine_types[] = { 700 { 701 .name = TYPE_MACHINE, 702 .parent = TYPE_OBJECT, 703 .abstract = true, 704 .class_init = machine_base_class_init, 705 .class_size = sizeof(MachineClass), 706 .instance_size = sizeof(MachineState), 707 }, { 708 .name = MACHINE_TYPE_NAME("smp-generic-valid"), 709 .parent = TYPE_MACHINE, 710 }, { 711 .name = MACHINE_TYPE_NAME("smp-generic-invalid"), 712 .parent = TYPE_MACHINE, 713 .class_init = machine_generic_invalid_class_init, 714 }, { 715 .name = MACHINE_TYPE_NAME("smp-with-dies"), 716 .parent = TYPE_MACHINE, 717 .class_init = machine_with_dies_class_init, 718 }, { 719 .name = MACHINE_TYPE_NAME("smp-with-clusters"), 720 .parent = TYPE_MACHINE, 721 .class_init = machine_with_clusters_class_init, 722 } 723 }; 724 725 DEFINE_TYPES(smp_machine_types) 726 727 int main(int argc, char *argv[]) 728 { 729 module_call_init(MODULE_INIT_QOM); 730 731 g_test_init(&argc, &argv, NULL); 732 733 g_test_add_data_func("/test-smp-parse/generic/valid", 734 MACHINE_TYPE_NAME("smp-generic-valid"), 735 test_generic_valid); 736 g_test_add_data_func("/test-smp-parse/generic/invalid", 737 MACHINE_TYPE_NAME("smp-generic-invalid"), 738 test_generic_invalid); 739 g_test_add_data_func("/test-smp-parse/with_dies", 740 MACHINE_TYPE_NAME("smp-with-dies"), 741 test_with_dies); 742 g_test_add_data_func("/test-smp-parse/with_clusters", 743 MACHINE_TYPE_NAME("smp-with-clusters"), 744 test_with_clusters); 745 746 g_test_run(); 747 748 return 0; 749 } 750