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 4096 /* set the max CPUs supported by the machine as 4096 */ 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 * Currently a 5-level topology hierarchy is supported on s390 ccw machines 80 * -drawers/books/sockets/cores/threads 81 */ 82 #define SMP_CONFIG_WITH_BOOKS_DRAWERS(ha, a, hb, b, hc, c, hd, \ 83 d, he, e, hf, f, hg, g) \ 84 { \ 85 .has_cpus = ha, .cpus = a, \ 86 .has_drawers = hb, .drawers = b, \ 87 .has_books = hc, .books = c, \ 88 .has_sockets = hd, .sockets = d, \ 89 .has_cores = he, .cores = e, \ 90 .has_threads = hf, .threads = f, \ 91 .has_maxcpus = hg, .maxcpus = g, \ 92 } 93 94 /* 95 * Currently QEMU supports up to a 7-level topology hierarchy, which is the 96 * QEMU's unified abstract representation of CPU topology. 97 * -drawers/books/sockets/dies/clusters/cores/threads 98 */ 99 #define SMP_CONFIG_WITH_FULL_TOPO(a, b, c, d, e, f, g, h, i) \ 100 { \ 101 .has_cpus = true, .cpus = a, \ 102 .has_drawers = true, .drawers = b, \ 103 .has_books = true, .books = c, \ 104 .has_sockets = true, .sockets = d, \ 105 .has_dies = true, .dies = e, \ 106 .has_clusters = true, .clusters = f, \ 107 .has_cores = true, .cores = g, \ 108 .has_threads = true, .threads = h, \ 109 .has_maxcpus = true, .maxcpus = i, \ 110 } 111 112 /** 113 * @config - the given SMP configuration 114 * @expect_prefer_sockets - the expected parsing result for the 115 * valid configuration, when sockets are preferred over cores 116 * @expect_prefer_cores - the expected parsing result for the 117 * valid configuration, when cores are preferred over sockets 118 * @expect_error - the expected error report when the given 119 * configuration is invalid 120 */ 121 typedef struct SMPTestData { 122 SMPConfiguration config; 123 CpuTopology expect_prefer_sockets; 124 CpuTopology expect_prefer_cores; 125 const char *expect_error; 126 } SMPTestData; 127 128 /* 129 * List all the possible valid sub-collections of the generic 5 130 * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads), 131 * then test the automatic calculation algorithm of the missing 132 * values in the parser. 133 */ 134 static const struct SMPTestData data_generic_valid[] = { 135 { 136 /* config: no configuration provided 137 * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */ 138 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0), 139 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), 140 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), 141 }, { 142 /* config: -smp 8 143 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8 144 * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */ 145 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0), 146 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8), 147 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8), 148 }, { 149 /* config: -smp sockets=2 150 * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */ 151 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0), 152 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), 153 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), 154 }, { 155 /* config: -smp cores=4 156 * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */ 157 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0), 158 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), 159 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), 160 }, { 161 /* config: -smp threads=2 162 * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */ 163 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0), 164 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), 165 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), 166 }, { 167 /* config: -smp maxcpus=16 168 * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16 169 * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */ 170 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16), 171 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16), 172 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16), 173 }, { 174 /* config: -smp 8,sockets=2 175 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 176 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0), 177 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 178 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 179 }, { 180 /* config: -smp 8,cores=4 181 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 182 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0), 183 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 184 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 185 }, { 186 /* config: -smp 8,threads=2 187 * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8 188 * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 189 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0), 190 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8), 191 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 192 }, { 193 /* config: -smp 8,maxcpus=16 194 * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16 195 * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */ 196 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16), 197 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16), 198 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16), 199 }, { 200 /* config: -smp sockets=2,cores=4 201 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 202 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0), 203 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 204 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 205 }, { 206 /* config: -smp sockets=2,threads=2 207 * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */ 208 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0), 209 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), 210 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), 211 }, { 212 /* config: -smp sockets=2,maxcpus=16 213 * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */ 214 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16), 215 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), 216 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), 217 }, { 218 /* config: -smp cores=4,threads=2 219 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 220 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0), 221 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 222 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 223 }, { 224 /* config: -smp cores=4,maxcpus=16 225 * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */ 226 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16), 227 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), 228 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), 229 }, { 230 /* config: -smp threads=2,maxcpus=16 231 * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16 232 * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */ 233 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16), 234 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16), 235 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16), 236 }, { 237 /* config: -smp 8,sockets=2,cores=4 238 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 239 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0), 240 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 241 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 242 }, { 243 /* config: -smp 8,sockets=2,threads=2 244 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */ 245 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0), 246 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 247 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 248 }, { 249 /* config: -smp 8,sockets=2,maxcpus=16 250 * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */ 251 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16), 252 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), 253 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), 254 }, { 255 /* config: -smp 8,cores=4,threads=2 256 * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */ 257 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0), 258 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 259 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), 260 }, { 261 /* config: -smp 8,cores=4,maxcpus=16 262 * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */ 263 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16), 264 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), 265 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), 266 }, { 267 /* config: -smp 8,threads=2,maxcpus=16 268 * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16 269 * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */ 270 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16), 271 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16), 272 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16), 273 }, { 274 /* config: -smp sockets=2,cores=4,threads=2 275 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 276 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0), 277 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 278 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 279 }, { 280 /* config: -smp sockets=2,cores=4,maxcpus=16 281 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 282 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16), 283 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 284 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 285 }, { 286 /* config: -smp sockets=2,threads=2,maxcpus=16 287 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 288 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16), 289 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 290 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 291 }, { 292 /* config: -smp cores=4,threads=2,maxcpus=16 293 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 294 .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16), 295 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 296 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 297 }, { 298 /* config: -smp 8,sockets=2,cores=4,threads=1 299 * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */ 300 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0), 301 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 302 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), 303 }, { 304 /* config: -smp 8,sockets=2,cores=4,maxcpus=16 305 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 306 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16), 307 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 308 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 309 }, { 310 /* config: -smp 8,sockets=2,threads=2,maxcpus=16 311 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 312 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16), 313 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 314 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 315 }, { 316 /* config: -smp 8,cores=4,threads=2,maxcpus=16 317 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 318 .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16), 319 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 320 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 321 }, { 322 /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16 323 * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */ 324 .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16), 325 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 326 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), 327 }, { 328 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16 329 * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */ 330 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16), 331 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 332 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), 333 }, { 334 /* 335 * Unsupported parameters are always allowed to be set to '1' 336 * config: -smp 8,books=1,drawers=1,sockets=2,modules=1,dies=1,cores=2,threads=2,maxcpus=8 337 * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */ 338 .config = SMP_CONFIG_WITH_FULL_TOPO(8, 1, 1, 2, 1, 1, 2, 2, 8), 339 .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 340 .expect_prefer_cores = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), 341 }, 342 }; 343 344 static const struct SMPTestData data_generic_invalid[] = { 345 { 346 /* config: -smp 2,dies=2 */ 347 .config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), 348 .expect_error = "dies > 1 not supported by this machine's CPU topology", 349 }, { 350 /* config: -smp 2,clusters=2 */ 351 .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0), 352 .expect_error = "clusters > 1 not supported by this machine's CPU topology", 353 }, { 354 /* config: -smp 2,books=2 */ 355 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, F, 0, T, 2, F, 356 0, F, 0, F, 0, F, 0), 357 .expect_error = "books > 1 not supported by this machine's CPU topology", 358 }, { 359 /* config: -smp 2,drawers=2 */ 360 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, T, 2, F, 0, F, 361 0, F, 0, F, 0, F, 0), 362 .expect_error = "drawers > 1 not supported by this machine's CPU topology", 363 }, { 364 /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */ 365 .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), 366 .expect_error = "Invalid CPU topology: " 367 "product of the hierarchy must match maxcpus: " 368 "sockets (2) * cores (4) * threads (2) " 369 "!= maxcpus (8)", 370 }, { 371 /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */ 372 .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16), 373 .expect_error = "Invalid CPU topology: " 374 "maxcpus must be equal to or greater than smp: " 375 "sockets (2) * cores (4) * threads (2) " 376 "== maxcpus (16) < smp_cpus (18)", 377 }, { 378 /* 379 * config: -smp 1 380 * The test machine should tweak the supported min CPUs to 381 * 2 (MIN_CPUS + 1) for testing. 382 */ 383 .config = SMP_CONFIG_GENERIC(T, MIN_CPUS, F, 0, F, 0, F, 0, F, 0), 384 .expect_error = "Invalid SMP CPUs 1. The min CPUs supported " 385 "by machine '" SMP_MACHINE_NAME "' is 2", 386 }, { 387 /* 388 * config: -smp 4096 389 * The test machine should tweak the supported max CPUs to 390 * 4095 (MAX_CPUS - 1) for testing. 391 */ 392 .config = SMP_CONFIG_GENERIC(T, 4096, F, 0, F, 0, F, 0, F, 0), 393 .expect_error = "Invalid SMP CPUs 4096. The max CPUs supported " 394 "by machine '" SMP_MACHINE_NAME "' is 4095", 395 }, 396 }; 397 398 static const struct SMPTestData data_with_dies_invalid[] = { 399 { 400 /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */ 401 .config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), 402 .expect_error = "Invalid CPU topology: " 403 "product of the hierarchy must match maxcpus: " 404 "sockets (2) * dies (2) * cores (4) * threads (2) " 405 "!= maxcpus (16)", 406 }, { 407 /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */ 408 .config = SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), 409 .expect_error = "Invalid CPU topology: " 410 "maxcpus must be equal to or greater than smp: " 411 "sockets (2) * dies (2) * cores (4) * threads (2) " 412 "== maxcpus (32) < smp_cpus (34)", 413 }, 414 }; 415 416 static const struct SMPTestData data_with_clusters_invalid[] = { 417 { 418 /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */ 419 .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16), 420 .expect_error = "Invalid CPU topology: " 421 "product of the hierarchy must match maxcpus: " 422 "sockets (2) * clusters (2) * cores (4) * threads (2) " 423 "!= maxcpus (16)", 424 }, { 425 /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */ 426 .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32), 427 .expect_error = "Invalid CPU topology: " 428 "maxcpus must be equal to or greater than smp: " 429 "sockets (2) * clusters (2) * cores (4) * threads (2) " 430 "== maxcpus (32) < smp_cpus (34)", 431 }, 432 }; 433 434 static const struct SMPTestData data_with_books_invalid[] = { 435 { 436 /* config: -smp 16,books=2,sockets=2,cores=4,threads=2,maxcpus=16 */ 437 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, F, 1, T, 2, T, 438 2, T, 4, T, 2, T, 16), 439 .expect_error = "Invalid CPU topology: " 440 "product of the hierarchy must match maxcpus: " 441 "books (2) * sockets (2) * cores (4) * threads (2) " 442 "!= maxcpus (16)", 443 }, { 444 /* config: -smp 34,books=2,sockets=2,cores=4,threads=2,maxcpus=32 */ 445 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, F, 1, T, 2, T, 446 2, T, 4, T, 2, T, 32), 447 .expect_error = "Invalid CPU topology: " 448 "maxcpus must be equal to or greater than smp: " 449 "books (2) * sockets (2) * cores (4) * threads (2) " 450 "== maxcpus (32) < smp_cpus (34)", 451 }, 452 }; 453 454 static const struct SMPTestData data_with_drawers_invalid[] = { 455 { 456 /* config: -smp 16,drawers=2,sockets=2,cores=4,threads=2,maxcpus=16 */ 457 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, T, 2, F, 1, T, 458 2, T, 4, T, 2, T, 16), 459 .expect_error = "Invalid CPU topology: " 460 "product of the hierarchy must match maxcpus: " 461 "drawers (2) * sockets (2) * cores (4) * threads (2) " 462 "!= maxcpus (16)", 463 }, { 464 /* config: -smp 34,drawers=2,sockets=2,cores=4,threads=2,maxcpus=32 */ 465 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, T, 2, F, 1, T, 466 2, T, 4, T, 2, T, 32), 467 .expect_error = "Invalid CPU topology: " 468 "maxcpus must be equal to or greater than smp: " 469 "drawers (2) * sockets (2) * cores (4) * threads (2) " 470 "== maxcpus (32) < smp_cpus (34)", 471 }, 472 }; 473 474 static const struct SMPTestData data_with_drawers_books_invalid[] = { 475 { 476 /* 477 * config: -smp 200,drawers=2,books=2,sockets=2,cores=4,\ 478 * threads=2,maxcpus=200 479 */ 480 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 200, T, 3, T, 5, T, 481 2, T, 4, T, 2, T, 200), 482 .expect_error = "Invalid CPU topology: " 483 "product of the hierarchy must match maxcpus: " 484 "drawers (3) * books (5) * sockets (2) * " 485 "cores (4) * threads (2) != maxcpus (200)", 486 }, { 487 /* 488 * config: -smp 242,drawers=2,books=2,sockets=2,cores=4,\ 489 * threads=2,maxcpus=240 490 */ 491 .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 242, T, 3, T, 5, T, 492 2, T, 4, T, 2, T, 240), 493 .expect_error = "Invalid CPU topology: " 494 "maxcpus must be equal to or greater than smp: " 495 "drawers (3) * books (5) * sockets (2) * " 496 "cores (4) * threads (2) " 497 "== maxcpus (240) < smp_cpus (242)", 498 }, 499 }; 500 501 static const struct SMPTestData data_full_topo_invalid[] = { 502 { 503 /* 504 * config: -smp 200,drawers=3,books=5,sockets=2,dies=4,\ 505 * clusters=2,cores=7,threads=2,maxcpus=200 506 */ 507 .config = SMP_CONFIG_WITH_FULL_TOPO(200, 3, 5, 2, 4, 2, 7, 2, 200), 508 .expect_error = "Invalid CPU topology: " 509 "product of the hierarchy must match maxcpus: " 510 "drawers (3) * books (5) * sockets (2) * dies (4) * " 511 "clusters (2) * cores (7) * threads (2) " 512 "!= maxcpus (200)", 513 }, { 514 /* 515 * config: -smp 3361,drawers=3,books=5,sockets=2,dies=4,\ 516 * clusters=2,cores=7,threads=2,maxcpus=3360 517 */ 518 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 2, 3360), 519 .expect_error = "Invalid CPU topology: " 520 "maxcpus must be equal to or greater than smp: " 521 "drawers (3) * books (5) * sockets (2) * dies (4) * " 522 "clusters (2) * cores (7) * threads (2) " 523 "== maxcpus (3360) < smp_cpus (3361)", 524 }, { 525 /* 526 * config: -smp 1,drawers=3,books=5,sockets=2,dies=4,\ 527 * clusters=2,cores=7,threads=3,maxcpus=5040 528 */ 529 .config = SMP_CONFIG_WITH_FULL_TOPO(3361, 3, 5, 2, 4, 2, 7, 3, 5040), 530 .expect_error = "Invalid SMP CPUs 5040. The max CPUs supported " 531 "by machine '" SMP_MACHINE_NAME "' is 4096", 532 }, 533 }; 534 535 static const struct SMPTestData data_zero_topo_invalid[] = { 536 { 537 /* 538 * Test "cpus=0". 539 * config: -smp 0,drawers=1,books=1,sockets=1,dies=1,\ 540 * clusters=1,cores=1,threads=1,maxcpus=1 541 */ 542 .config = SMP_CONFIG_WITH_FULL_TOPO(0, 1, 1, 1, 1, 1, 1, 1, 1), 543 .expect_error = "Invalid CPU topology: CPU topology parameters must " 544 "be greater than zero", 545 }, { 546 /* 547 * Test "drawers=0". 548 * config: -smp 1,drawers=0,books=1,sockets=1,dies=1,\ 549 * clusters=1,cores=1,threads=1,maxcpus=1 550 */ 551 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 0, 1, 1, 1, 1, 1, 1, 1), 552 .expect_error = "Invalid CPU topology: CPU topology parameters must " 553 "be greater than zero", 554 }, { 555 /* 556 * Test "books=0". 557 * config: -smp 1,drawers=1,books=0,sockets=1,dies=1,\ 558 * clusters=1,cores=1,threads=1,maxcpus=1 559 */ 560 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 0, 1, 1, 1, 1, 1, 1), 561 .expect_error = "Invalid CPU topology: CPU topology parameters must " 562 "be greater than zero", 563 }, { 564 /* 565 * Test "sockets=0". 566 * config: -smp 1,drawers=1,books=1,sockets=0,dies=1,\ 567 * clusters=1,cores=1,threads=1,maxcpus=1 568 */ 569 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 0, 1, 1, 1, 1, 1), 570 .expect_error = "Invalid CPU topology: CPU topology parameters must " 571 "be greater than zero", 572 }, { 573 /* 574 * Test "dies=0". 575 * config: -smp 1,drawers=1,books=1,sockets=1,dies=0,\ 576 * clusters=1,cores=1,threads=1,maxcpus=1 577 */ 578 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 0, 1, 1, 1, 1), 579 .expect_error = "Invalid CPU topology: CPU topology parameters must " 580 "be greater than zero", 581 }, { 582 /* 583 * Test "clusters=0". 584 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\ 585 * clusters=0,cores=1,threads=1,maxcpus=1 586 */ 587 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 0, 1, 1, 1), 588 .expect_error = "Invalid CPU topology: CPU topology parameters must " 589 "be greater than zero", 590 }, { 591 /* 592 * Test "cores=0". 593 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\ 594 * clusters=1,cores=0,threads=1,maxcpus=1 595 */ 596 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 0, 1, 1), 597 .expect_error = "Invalid CPU topology: CPU topology parameters must " 598 "be greater than zero", 599 }, { 600 /* 601 * Test "threads=0". 602 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\ 603 * clusters=1,cores=1,threads=0,maxcpus=1 604 */ 605 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 0, 1), 606 .expect_error = "Invalid CPU topology: CPU topology parameters must " 607 "be greater than zero", 608 }, { 609 /* 610 * Test "maxcpus=0". 611 * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\ 612 * clusters=1,cores=1,threads=1,maxcpus=0 613 */ 614 .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 1, 0), 615 .expect_error = "Invalid CPU topology: CPU topology parameters must " 616 "be greater than zero", 617 }, 618 }; 619 620 static char *smp_config_to_string(const SMPConfiguration *config) 621 { 622 return g_strdup_printf( 623 "(SMPConfiguration) {\n" 624 " .has_cpus = %5s, cpus = %" PRId64 ",\n" 625 " .has_drawers = %5s, drawers = %" PRId64 ",\n" 626 " .has_books = %5s, books = %" PRId64 ",\n" 627 " .has_sockets = %5s, sockets = %" PRId64 ",\n" 628 " .has_dies = %5s, dies = %" PRId64 ",\n" 629 " .has_clusters = %5s, clusters = %" PRId64 ",\n" 630 " .has_cores = %5s, cores = %" PRId64 ",\n" 631 " .has_threads = %5s, threads = %" PRId64 ",\n" 632 " .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n" 633 "}", 634 config->has_cpus ? "true" : "false", config->cpus, 635 config->has_drawers ? "true" : "false", config->drawers, 636 config->has_books ? "true" : "false", config->books, 637 config->has_sockets ? "true" : "false", config->sockets, 638 config->has_dies ? "true" : "false", config->dies, 639 config->has_clusters ? "true" : "false", config->clusters, 640 config->has_cores ? "true" : "false", config->cores, 641 config->has_threads ? "true" : "false", config->threads, 642 config->has_maxcpus ? "true" : "false", config->maxcpus); 643 } 644 645 /* Use the different calculation than machine_topo_get_threads_per_socket(). */ 646 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo) 647 { 648 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */ 649 if (!topo->drawers || !topo->books || !topo->sockets) { 650 return 0; 651 } else { 652 return topo->max_cpus / topo->drawers / topo->books / topo->sockets; 653 } 654 } 655 656 /* Use the different calculation than machine_topo_get_cores_per_socket(). */ 657 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo) 658 { 659 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */ 660 if (!topo->threads) { 661 return 0; 662 } else { 663 return cpu_topology_get_threads_per_socket(topo) / topo->threads; 664 } 665 } 666 667 static char *cpu_topology_to_string(const CpuTopology *topo, 668 unsigned int threads_per_socket, 669 unsigned int cores_per_socket, 670 bool has_clusters) 671 { 672 return g_strdup_printf( 673 "(CpuTopology) {\n" 674 " .cpus = %u,\n" 675 " .drawers = %u,\n" 676 " .books = %u,\n" 677 " .sockets = %u,\n" 678 " .dies = %u,\n" 679 " .clusters = %u,\n" 680 " .cores = %u,\n" 681 " .threads = %u,\n" 682 " .max_cpus = %u,\n" 683 " .threads_per_socket = %u,\n" 684 " .cores_per_socket = %u,\n" 685 " .has_clusters = %s,\n" 686 "}", 687 topo->cpus, topo->drawers, topo->books, 688 topo->sockets, topo->dies, topo->clusters, 689 topo->cores, topo->threads, topo->max_cpus, 690 threads_per_socket, cores_per_socket, 691 has_clusters ? "true" : "false"); 692 } 693 694 static void check_parse(MachineState *ms, const SMPConfiguration *config, 695 const CpuTopology *expect_topo, const char *expect_err, 696 bool is_valid) 697 { 698 MachineClass *mc = MACHINE_GET_CLASS(ms); 699 g_autofree char *config_str = smp_config_to_string(config); 700 g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL; 701 unsigned int expect_threads_per_socket, expect_cores_per_socket; 702 unsigned int ms_threads_per_socket, ms_cores_per_socket; 703 Error *err = NULL; 704 705 expect_threads_per_socket = 706 cpu_topology_get_threads_per_socket(expect_topo); 707 expect_cores_per_socket = 708 cpu_topology_get_cores_per_socket(expect_topo); 709 expect_topo_str = cpu_topology_to_string(expect_topo, 710 expect_threads_per_socket, 711 expect_cores_per_socket, 712 config->has_clusters); 713 714 /* call the generic parser */ 715 machine_parse_smp_config(ms, config, &err); 716 717 ms_threads_per_socket = machine_topo_get_threads_per_socket(ms); 718 ms_cores_per_socket = machine_topo_get_cores_per_socket(ms); 719 output_topo_str = cpu_topology_to_string(&ms->smp, 720 ms_threads_per_socket, 721 ms_cores_per_socket, 722 mc->smp_props.has_clusters); 723 724 /* when the configuration is supposed to be valid */ 725 if (is_valid) { 726 if ((err == NULL) && 727 (ms->smp.cpus == expect_topo->cpus) && 728 (ms->smp.drawers == expect_topo->drawers) && 729 (ms->smp.books == expect_topo->books) && 730 (ms->smp.sockets == expect_topo->sockets) && 731 (ms->smp.dies == expect_topo->dies) && 732 (ms->smp.clusters == expect_topo->clusters) && 733 (ms->smp.cores == expect_topo->cores) && 734 (ms->smp.threads == expect_topo->threads) && 735 (ms->smp.max_cpus == expect_topo->max_cpus) && 736 (ms_threads_per_socket == expect_threads_per_socket) && 737 (ms_cores_per_socket == expect_cores_per_socket) && 738 (mc->smp_props.has_clusters == config->has_clusters)) { 739 return; 740 } 741 742 if (err != NULL) { 743 g_printerr("Test smp_parse failed!\n" 744 "Input configuration: %s\n" 745 "Should be valid: yes\n" 746 "Expected topology: %s\n\n" 747 "Result is valid: no\n" 748 "Output error report: %s\n", 749 config_str, expect_topo_str, error_get_pretty(err)); 750 goto end; 751 } 752 753 g_printerr("Test smp_parse failed!\n" 754 "Input configuration: %s\n" 755 "Should be valid: yes\n" 756 "Expected topology: %s\n\n" 757 "Result is valid: yes\n" 758 "Output topology: %s\n", 759 config_str, expect_topo_str, output_topo_str); 760 goto end; 761 } 762 763 /* when the configuration is supposed to be invalid */ 764 if (err != NULL) { 765 if (expect_err == NULL || 766 g_str_equal(expect_err, error_get_pretty(err))) { 767 error_free(err); 768 return; 769 } 770 771 g_printerr("Test smp_parse failed!\n" 772 "Input configuration: %s\n" 773 "Should be valid: no\n" 774 "Expected error report: %s\n\n" 775 "Result is valid: no\n" 776 "Output error report: %s\n", 777 config_str, expect_err, error_get_pretty(err)); 778 goto end; 779 } 780 781 g_printerr("Test smp_parse failed!\n" 782 "Input configuration: %s\n" 783 "Should be valid: no\n" 784 "Expected error report: %s\n\n" 785 "Result is valid: yes\n" 786 "Output topology: %s\n", 787 config_str, expect_err, output_topo_str); 788 789 end: 790 if (err != NULL) { 791 error_free(err); 792 } 793 794 abort(); 795 } 796 797 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) 798 { 799 MachineClass *mc = MACHINE_GET_CLASS(ms); 800 801 mc->smp_props.prefer_sockets = true; 802 check_parse(ms, &data->config, &data->expect_prefer_sockets, 803 data->expect_error, is_valid); 804 805 mc->smp_props.prefer_sockets = false; 806 check_parse(ms, &data->config, &data->expect_prefer_cores, 807 data->expect_error, is_valid); 808 } 809 810 /* The parsed results of the unsupported parameters should be 1 */ 811 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) 812 { 813 if (!mc->smp_props.dies_supported) { 814 data->expect_prefer_sockets.dies = 1; 815 data->expect_prefer_cores.dies = 1; 816 } 817 818 if (!mc->smp_props.clusters_supported) { 819 data->expect_prefer_sockets.clusters = 1; 820 data->expect_prefer_cores.clusters = 1; 821 } 822 823 if (!mc->smp_props.books_supported) { 824 data->expect_prefer_sockets.books = 1; 825 data->expect_prefer_cores.books = 1; 826 } 827 828 if (!mc->smp_props.drawers_supported) { 829 data->expect_prefer_sockets.drawers = 1; 830 data->expect_prefer_cores.drawers = 1; 831 } 832 } 833 834 static void machine_base_class_init(ObjectClass *oc, void *data) 835 { 836 MachineClass *mc = MACHINE_CLASS(oc); 837 838 mc->min_cpus = MIN_CPUS; 839 mc->max_cpus = MAX_CPUS; 840 841 mc->name = g_strdup(SMP_MACHINE_NAME); 842 } 843 844 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) 845 { 846 MachineClass *mc = MACHINE_CLASS(oc); 847 848 /* Force invalid min CPUs and max CPUs */ 849 mc->min_cpus = MIN_CPUS + 1; 850 mc->max_cpus = MAX_CPUS - 1; 851 } 852 853 static void machine_with_dies_class_init(ObjectClass *oc, void *data) 854 { 855 MachineClass *mc = MACHINE_CLASS(oc); 856 857 mc->smp_props.dies_supported = true; 858 } 859 860 static void machine_with_clusters_class_init(ObjectClass *oc, void *data) 861 { 862 MachineClass *mc = MACHINE_CLASS(oc); 863 864 mc->smp_props.clusters_supported = true; 865 } 866 867 static void machine_with_books_class_init(ObjectClass *oc, void *data) 868 { 869 MachineClass *mc = MACHINE_CLASS(oc); 870 871 mc->smp_props.books_supported = true; 872 } 873 874 static void machine_with_drawers_class_init(ObjectClass *oc, void *data) 875 { 876 MachineClass *mc = MACHINE_CLASS(oc); 877 878 mc->smp_props.drawers_supported = true; 879 } 880 881 static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data) 882 { 883 MachineClass *mc = MACHINE_CLASS(oc); 884 885 mc->smp_props.drawers_supported = true; 886 mc->smp_props.books_supported = true; 887 } 888 889 static void machine_full_topo_class_init(ObjectClass *oc, void *data) 890 { 891 MachineClass *mc = MACHINE_CLASS(oc); 892 893 mc->smp_props.drawers_supported = true; 894 mc->smp_props.books_supported = true; 895 mc->smp_props.dies_supported = true; 896 mc->smp_props.clusters_supported = true; 897 } 898 899 static void test_generic_valid(const void *opaque) 900 { 901 const char *machine_type = opaque; 902 Object *obj = object_new(machine_type); 903 MachineState *ms = MACHINE(obj); 904 MachineClass *mc = MACHINE_GET_CLASS(obj); 905 SMPTestData data = {}; 906 int i; 907 908 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 909 data = data_generic_valid[i]; 910 unsupported_params_init(mc, &data); 911 912 smp_parse_test(ms, &data, true); 913 } 914 915 object_unref(obj); 916 } 917 918 static void test_generic_invalid(const void *opaque) 919 { 920 const char *machine_type = opaque; 921 Object *obj = object_new(machine_type); 922 MachineState *ms = MACHINE(obj); 923 MachineClass *mc = MACHINE_GET_CLASS(obj); 924 SMPTestData data = {}; 925 int i; 926 927 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { 928 data = data_generic_invalid[i]; 929 unsupported_params_init(mc, &data); 930 931 smp_parse_test(ms, &data, false); 932 } 933 934 object_unref(obj); 935 } 936 937 static void test_with_dies(const void *opaque) 938 { 939 const char *machine_type = opaque; 940 Object *obj = object_new(machine_type); 941 MachineState *ms = MACHINE(obj); 942 MachineClass *mc = MACHINE_GET_CLASS(obj); 943 SMPTestData data = {}; 944 unsigned int num_dies = 2; 945 int i; 946 947 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 948 data = data_generic_valid[i]; 949 unsupported_params_init(mc, &data); 950 951 /* when dies parameter is omitted, it will be set as 1 */ 952 data.expect_prefer_sockets.dies = 1; 953 data.expect_prefer_cores.dies = 1; 954 955 smp_parse_test(ms, &data, true); 956 957 /* when dies parameter is specified */ 958 data.config.has_dies = true; 959 data.config.dies = num_dies; 960 if (data.config.has_cpus) { 961 data.config.cpus *= num_dies; 962 } 963 if (data.config.has_maxcpus) { 964 data.config.maxcpus *= num_dies; 965 } 966 967 data.expect_prefer_sockets.dies = num_dies; 968 data.expect_prefer_sockets.cpus *= num_dies; 969 data.expect_prefer_sockets.max_cpus *= num_dies; 970 data.expect_prefer_cores.dies = num_dies; 971 data.expect_prefer_cores.cpus *= num_dies; 972 data.expect_prefer_cores.max_cpus *= num_dies; 973 974 smp_parse_test(ms, &data, true); 975 } 976 977 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { 978 data = data_with_dies_invalid[i]; 979 unsupported_params_init(mc, &data); 980 981 smp_parse_test(ms, &data, false); 982 } 983 984 object_unref(obj); 985 } 986 987 static void test_with_clusters(const void *opaque) 988 { 989 const char *machine_type = opaque; 990 Object *obj = object_new(machine_type); 991 MachineState *ms = MACHINE(obj); 992 MachineClass *mc = MACHINE_GET_CLASS(obj); 993 SMPTestData data = {}; 994 unsigned int num_clusters = 2; 995 int i; 996 997 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 998 data = data_generic_valid[i]; 999 unsupported_params_init(mc, &data); 1000 1001 /* when clusters parameter is omitted, it will be set as 1 */ 1002 data.expect_prefer_sockets.clusters = 1; 1003 data.expect_prefer_cores.clusters = 1; 1004 1005 smp_parse_test(ms, &data, true); 1006 1007 /* when clusters parameter is specified */ 1008 data.config.has_clusters = true; 1009 data.config.clusters = num_clusters; 1010 if (data.config.has_cpus) { 1011 data.config.cpus *= num_clusters; 1012 } 1013 if (data.config.has_maxcpus) { 1014 data.config.maxcpus *= num_clusters; 1015 } 1016 1017 data.expect_prefer_sockets.clusters = num_clusters; 1018 data.expect_prefer_sockets.cpus *= num_clusters; 1019 data.expect_prefer_sockets.max_cpus *= num_clusters; 1020 data.expect_prefer_cores.clusters = num_clusters; 1021 data.expect_prefer_cores.cpus *= num_clusters; 1022 data.expect_prefer_cores.max_cpus *= num_clusters; 1023 1024 smp_parse_test(ms, &data, true); 1025 } 1026 1027 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) { 1028 data = data_with_clusters_invalid[i]; 1029 unsupported_params_init(mc, &data); 1030 1031 smp_parse_test(ms, &data, false); 1032 } 1033 1034 object_unref(obj); 1035 } 1036 1037 static void test_with_books(const void *opaque) 1038 { 1039 const char *machine_type = opaque; 1040 Object *obj = object_new(machine_type); 1041 MachineState *ms = MACHINE(obj); 1042 MachineClass *mc = MACHINE_GET_CLASS(obj); 1043 SMPTestData data = {}; 1044 unsigned int num_books = 2; 1045 int i; 1046 1047 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 1048 data = data_generic_valid[i]; 1049 unsupported_params_init(mc, &data); 1050 1051 /* when books parameter is omitted, it will be set as 1 */ 1052 data.expect_prefer_sockets.books = 1; 1053 data.expect_prefer_cores.books = 1; 1054 1055 smp_parse_test(ms, &data, true); 1056 1057 /* when books parameter is specified */ 1058 data.config.has_books = true; 1059 data.config.books = num_books; 1060 if (data.config.has_cpus) { 1061 data.config.cpus *= num_books; 1062 } 1063 if (data.config.has_maxcpus) { 1064 data.config.maxcpus *= num_books; 1065 } 1066 1067 data.expect_prefer_sockets.books = num_books; 1068 data.expect_prefer_sockets.cpus *= num_books; 1069 data.expect_prefer_sockets.max_cpus *= num_books; 1070 data.expect_prefer_cores.books = num_books; 1071 data.expect_prefer_cores.cpus *= num_books; 1072 data.expect_prefer_cores.max_cpus *= num_books; 1073 1074 smp_parse_test(ms, &data, true); 1075 } 1076 1077 for (i = 0; i < ARRAY_SIZE(data_with_books_invalid); i++) { 1078 data = data_with_books_invalid[i]; 1079 unsupported_params_init(mc, &data); 1080 1081 smp_parse_test(ms, &data, false); 1082 } 1083 1084 object_unref(obj); 1085 } 1086 1087 static void test_with_drawers(const void *opaque) 1088 { 1089 const char *machine_type = opaque; 1090 Object *obj = object_new(machine_type); 1091 MachineState *ms = MACHINE(obj); 1092 MachineClass *mc = MACHINE_GET_CLASS(obj); 1093 SMPTestData data = {}; 1094 unsigned int num_drawers = 2; 1095 int i; 1096 1097 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 1098 data = data_generic_valid[i]; 1099 unsupported_params_init(mc, &data); 1100 1101 /* when drawers parameter is omitted, it will be set as 1 */ 1102 data.expect_prefer_sockets.drawers = 1; 1103 data.expect_prefer_cores.drawers = 1; 1104 1105 smp_parse_test(ms, &data, true); 1106 1107 /* when drawers parameter is specified */ 1108 data.config.has_drawers = true; 1109 data.config.drawers = num_drawers; 1110 if (data.config.has_cpus) { 1111 data.config.cpus *= num_drawers; 1112 } 1113 if (data.config.has_maxcpus) { 1114 data.config.maxcpus *= num_drawers; 1115 } 1116 1117 data.expect_prefer_sockets.drawers = num_drawers; 1118 data.expect_prefer_sockets.cpus *= num_drawers; 1119 data.expect_prefer_sockets.max_cpus *= num_drawers; 1120 data.expect_prefer_cores.drawers = num_drawers; 1121 data.expect_prefer_cores.cpus *= num_drawers; 1122 data.expect_prefer_cores.max_cpus *= num_drawers; 1123 1124 smp_parse_test(ms, &data, true); 1125 } 1126 1127 for (i = 0; i < ARRAY_SIZE(data_with_drawers_invalid); i++) { 1128 data = data_with_drawers_invalid[i]; 1129 unsupported_params_init(mc, &data); 1130 1131 smp_parse_test(ms, &data, false); 1132 } 1133 1134 object_unref(obj); 1135 } 1136 1137 static void test_with_drawers_books(const void *opaque) 1138 { 1139 const char *machine_type = opaque; 1140 Object *obj = object_new(machine_type); 1141 MachineState *ms = MACHINE(obj); 1142 MachineClass *mc = MACHINE_GET_CLASS(obj); 1143 SMPTestData data = {}; 1144 unsigned int num_drawers = 5, num_books = 3; 1145 int i; 1146 1147 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 1148 data = data_generic_valid[i]; 1149 unsupported_params_init(mc, &data); 1150 1151 /* 1152 * when drawers and books parameters are omitted, they will 1153 * be both set as 1. 1154 */ 1155 data.expect_prefer_sockets.drawers = 1; 1156 data.expect_prefer_sockets.books = 1; 1157 data.expect_prefer_cores.drawers = 1; 1158 data.expect_prefer_cores.books = 1; 1159 1160 smp_parse_test(ms, &data, true); 1161 1162 /* when drawers and books parameters are both specified */ 1163 data.config.has_drawers = true; 1164 data.config.drawers = num_drawers; 1165 data.config.has_books = true; 1166 data.config.books = num_books; 1167 1168 if (data.config.has_cpus) { 1169 data.config.cpus *= num_drawers * num_books; 1170 } 1171 if (data.config.has_maxcpus) { 1172 data.config.maxcpus *= num_drawers * num_books; 1173 } 1174 1175 data.expect_prefer_sockets.drawers = num_drawers; 1176 data.expect_prefer_sockets.books = num_books; 1177 data.expect_prefer_sockets.cpus *= num_drawers * num_books; 1178 data.expect_prefer_sockets.max_cpus *= num_drawers * num_books; 1179 1180 data.expect_prefer_cores.drawers = num_drawers; 1181 data.expect_prefer_cores.books = num_books; 1182 data.expect_prefer_cores.cpus *= num_drawers * num_books; 1183 data.expect_prefer_cores.max_cpus *= num_drawers * num_books; 1184 1185 smp_parse_test(ms, &data, true); 1186 } 1187 1188 for (i = 0; i < ARRAY_SIZE(data_with_drawers_books_invalid); i++) { 1189 data = data_with_drawers_books_invalid[i]; 1190 unsupported_params_init(mc, &data); 1191 1192 smp_parse_test(ms, &data, false); 1193 } 1194 1195 object_unref(obj); 1196 } 1197 1198 static void test_full_topo(const void *opaque) 1199 { 1200 const char *machine_type = opaque; 1201 Object *obj = object_new(machine_type); 1202 MachineState *ms = MACHINE(obj); 1203 MachineClass *mc = MACHINE_GET_CLASS(obj); 1204 SMPTestData data = {}; 1205 unsigned int drawers = 5, books = 3, dies = 2, clusters = 7, multiplier; 1206 int i; 1207 1208 multiplier = drawers * books * dies * clusters; 1209 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 1210 data = data_generic_valid[i]; 1211 unsupported_params_init(mc, &data); 1212 1213 /* 1214 * when drawers, books, dies and clusters parameters are omitted, 1215 * they will be set as 1. 1216 */ 1217 data.expect_prefer_sockets.drawers = 1; 1218 data.expect_prefer_sockets.books = 1; 1219 data.expect_prefer_sockets.dies = 1; 1220 data.expect_prefer_sockets.clusters = 1; 1221 data.expect_prefer_cores.drawers = 1; 1222 data.expect_prefer_cores.books = 1; 1223 data.expect_prefer_cores.dies = 1; 1224 data.expect_prefer_cores.clusters = 1; 1225 1226 smp_parse_test(ms, &data, true); 1227 1228 /* when drawers, books, dies and clusters parameters are specified. */ 1229 data.config.has_drawers = true; 1230 data.config.drawers = drawers; 1231 data.config.has_books = true; 1232 data.config.books = books; 1233 data.config.has_dies = true; 1234 data.config.dies = dies; 1235 data.config.has_clusters = true; 1236 data.config.clusters = clusters; 1237 1238 if (data.config.has_cpus) { 1239 data.config.cpus *= multiplier; 1240 } 1241 if (data.config.has_maxcpus) { 1242 data.config.maxcpus *= multiplier; 1243 } 1244 1245 data.expect_prefer_sockets.drawers = drawers; 1246 data.expect_prefer_sockets.books = books; 1247 data.expect_prefer_sockets.dies = dies; 1248 data.expect_prefer_sockets.clusters = clusters; 1249 data.expect_prefer_sockets.cpus *= multiplier; 1250 data.expect_prefer_sockets.max_cpus *= multiplier; 1251 1252 data.expect_prefer_cores.drawers = drawers; 1253 data.expect_prefer_cores.books = books; 1254 data.expect_prefer_cores.dies = dies; 1255 data.expect_prefer_cores.clusters = clusters; 1256 data.expect_prefer_cores.cpus *= multiplier; 1257 data.expect_prefer_cores.max_cpus *= multiplier; 1258 1259 smp_parse_test(ms, &data, true); 1260 } 1261 1262 for (i = 0; i < ARRAY_SIZE(data_full_topo_invalid); i++) { 1263 data = data_full_topo_invalid[i]; 1264 unsupported_params_init(mc, &data); 1265 1266 smp_parse_test(ms, &data, false); 1267 } 1268 1269 for (i = 0; i < ARRAY_SIZE(data_zero_topo_invalid); i++) { 1270 data = data_zero_topo_invalid[i]; 1271 unsupported_params_init(mc, &data); 1272 1273 smp_parse_test(ms, &data, false); 1274 } 1275 1276 object_unref(obj); 1277 } 1278 1279 /* Type info of the tested machine */ 1280 static const TypeInfo smp_machine_types[] = { 1281 { 1282 .name = TYPE_MACHINE, 1283 .parent = TYPE_OBJECT, 1284 .abstract = true, 1285 .class_init = machine_base_class_init, 1286 .class_size = sizeof(MachineClass), 1287 .instance_size = sizeof(MachineState), 1288 }, { 1289 .name = MACHINE_TYPE_NAME("smp-generic-valid"), 1290 .parent = TYPE_MACHINE, 1291 }, { 1292 .name = MACHINE_TYPE_NAME("smp-generic-invalid"), 1293 .parent = TYPE_MACHINE, 1294 .class_init = machine_generic_invalid_class_init, 1295 }, { 1296 .name = MACHINE_TYPE_NAME("smp-with-dies"), 1297 .parent = TYPE_MACHINE, 1298 .class_init = machine_with_dies_class_init, 1299 }, { 1300 .name = MACHINE_TYPE_NAME("smp-with-clusters"), 1301 .parent = TYPE_MACHINE, 1302 .class_init = machine_with_clusters_class_init, 1303 }, { 1304 .name = MACHINE_TYPE_NAME("smp-with-books"), 1305 .parent = TYPE_MACHINE, 1306 .class_init = machine_with_books_class_init, 1307 }, { 1308 .name = MACHINE_TYPE_NAME("smp-with-drawers"), 1309 .parent = TYPE_MACHINE, 1310 .class_init = machine_with_drawers_class_init, 1311 }, { 1312 .name = MACHINE_TYPE_NAME("smp-with-drawers-books"), 1313 .parent = TYPE_MACHINE, 1314 .class_init = machine_with_drawers_books_class_init, 1315 }, { 1316 .name = MACHINE_TYPE_NAME("smp-full-topo"), 1317 .parent = TYPE_MACHINE, 1318 .class_init = machine_full_topo_class_init, 1319 } 1320 }; 1321 1322 DEFINE_TYPES(smp_machine_types) 1323 1324 int main(int argc, char *argv[]) 1325 { 1326 module_call_init(MODULE_INIT_QOM); 1327 1328 g_test_init(&argc, &argv, NULL); 1329 1330 g_test_add_data_func("/test-smp-parse/generic/valid", 1331 MACHINE_TYPE_NAME("smp-generic-valid"), 1332 test_generic_valid); 1333 g_test_add_data_func("/test-smp-parse/generic/invalid", 1334 MACHINE_TYPE_NAME("smp-generic-invalid"), 1335 test_generic_invalid); 1336 g_test_add_data_func("/test-smp-parse/with_dies", 1337 MACHINE_TYPE_NAME("smp-with-dies"), 1338 test_with_dies); 1339 g_test_add_data_func("/test-smp-parse/with_clusters", 1340 MACHINE_TYPE_NAME("smp-with-clusters"), 1341 test_with_clusters); 1342 g_test_add_data_func("/test-smp-parse/with_books", 1343 MACHINE_TYPE_NAME("smp-with-books"), 1344 test_with_books); 1345 g_test_add_data_func("/test-smp-parse/with_drawers", 1346 MACHINE_TYPE_NAME("smp-with-drawers"), 1347 test_with_drawers); 1348 g_test_add_data_func("/test-smp-parse/with_drawers_books", 1349 MACHINE_TYPE_NAME("smp-with-drawers-books"), 1350 test_with_drawers_books); 1351 g_test_add_data_func("/test-smp-parse/full", 1352 MACHINE_TYPE_NAME("smp-full-topo"), 1353 test_full_topo); 1354 1355 g_test_run(); 1356 1357 return 0; 1358 } 1359