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 /* Use the different calculation than machine_topo_get_threads_per_socket(). */ 398 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo) 399 { 400 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */ 401 if (!topo->sockets) { 402 return 0; 403 } else { 404 return topo->max_cpus / topo->sockets; 405 } 406 } 407 408 /* Use the different calculation than machine_topo_get_cores_per_socket(). */ 409 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo) 410 { 411 /* Check the divisor to avoid invalid topology examples causing SIGFPE. */ 412 if (!topo->threads) { 413 return 0; 414 } else { 415 return cpu_topology_get_threads_per_socket(topo) / topo->threads; 416 } 417 } 418 419 static char *cpu_topology_to_string(const CpuTopology *topo, 420 unsigned int threads_per_socket, 421 unsigned int cores_per_socket) 422 { 423 return g_strdup_printf( 424 "(CpuTopology) {\n" 425 " .cpus = %u,\n" 426 " .sockets = %u,\n" 427 " .dies = %u,\n" 428 " .clusters = %u,\n" 429 " .cores = %u,\n" 430 " .threads = %u,\n" 431 " .max_cpus = %u,\n" 432 " .threads_per_socket = %u,\n" 433 " .cores_per_socket = %u,\n" 434 "}", 435 topo->cpus, topo->sockets, topo->dies, topo->clusters, 436 topo->cores, topo->threads, topo->max_cpus, 437 threads_per_socket, cores_per_socket); 438 } 439 440 static void check_parse(MachineState *ms, const SMPConfiguration *config, 441 const CpuTopology *expect_topo, const char *expect_err, 442 bool is_valid) 443 { 444 g_autofree char *config_str = smp_config_to_string(config); 445 g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL; 446 unsigned int expect_threads_per_socket, expect_cores_per_socket; 447 unsigned int ms_threads_per_socket, ms_cores_per_socket; 448 Error *err = NULL; 449 450 expect_threads_per_socket = 451 cpu_topology_get_threads_per_socket(expect_topo); 452 expect_cores_per_socket = 453 cpu_topology_get_cores_per_socket(expect_topo); 454 expect_topo_str = cpu_topology_to_string(expect_topo, 455 expect_threads_per_socket, 456 expect_cores_per_socket); 457 458 /* call the generic parser */ 459 machine_parse_smp_config(ms, config, &err); 460 461 ms_threads_per_socket = machine_topo_get_threads_per_socket(ms); 462 ms_cores_per_socket = machine_topo_get_cores_per_socket(ms); 463 output_topo_str = cpu_topology_to_string(&ms->smp, ms_threads_per_socket, 464 ms_cores_per_socket); 465 466 /* when the configuration is supposed to be valid */ 467 if (is_valid) { 468 if ((err == NULL) && 469 (ms->smp.cpus == expect_topo->cpus) && 470 (ms->smp.sockets == expect_topo->sockets) && 471 (ms->smp.dies == expect_topo->dies) && 472 (ms->smp.clusters == expect_topo->clusters) && 473 (ms->smp.cores == expect_topo->cores) && 474 (ms->smp.threads == expect_topo->threads) && 475 (ms->smp.max_cpus == expect_topo->max_cpus) && 476 (ms_threads_per_socket == expect_threads_per_socket) && 477 (ms_cores_per_socket == expect_cores_per_socket)) { 478 return; 479 } 480 481 if (err != NULL) { 482 g_printerr("Test smp_parse failed!\n" 483 "Input configuration: %s\n" 484 "Should be valid: yes\n" 485 "Expected topology: %s\n\n" 486 "Result is valid: no\n" 487 "Output error report: %s\n", 488 config_str, expect_topo_str, error_get_pretty(err)); 489 goto end; 490 } 491 492 g_printerr("Test smp_parse failed!\n" 493 "Input configuration: %s\n" 494 "Should be valid: yes\n" 495 "Expected topology: %s\n\n" 496 "Result is valid: yes\n" 497 "Output topology: %s\n", 498 config_str, expect_topo_str, output_topo_str); 499 goto end; 500 } 501 502 /* when the configuration is supposed to be invalid */ 503 if (err != NULL) { 504 if (expect_err == NULL || 505 g_str_equal(expect_err, error_get_pretty(err))) { 506 error_free(err); 507 return; 508 } 509 510 g_printerr("Test smp_parse failed!\n" 511 "Input configuration: %s\n" 512 "Should be valid: no\n" 513 "Expected error report: %s\n\n" 514 "Result is valid: no\n" 515 "Output error report: %s\n", 516 config_str, expect_err, error_get_pretty(err)); 517 goto end; 518 } 519 520 g_printerr("Test smp_parse failed!\n" 521 "Input configuration: %s\n" 522 "Should be valid: no\n" 523 "Expected error report: %s\n\n" 524 "Result is valid: yes\n" 525 "Output topology: %s\n", 526 config_str, expect_err, output_topo_str); 527 528 end: 529 if (err != NULL) { 530 error_free(err); 531 } 532 533 abort(); 534 } 535 536 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid) 537 { 538 MachineClass *mc = MACHINE_GET_CLASS(ms); 539 540 mc->smp_props.prefer_sockets = true; 541 check_parse(ms, &data->config, &data->expect_prefer_sockets, 542 data->expect_error, is_valid); 543 544 mc->smp_props.prefer_sockets = false; 545 check_parse(ms, &data->config, &data->expect_prefer_cores, 546 data->expect_error, is_valid); 547 } 548 549 /* The parsed results of the unsupported parameters should be 1 */ 550 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) 551 { 552 if (!mc->smp_props.dies_supported) { 553 data->expect_prefer_sockets.dies = 1; 554 data->expect_prefer_cores.dies = 1; 555 } 556 557 if (!mc->smp_props.clusters_supported) { 558 data->expect_prefer_sockets.clusters = 1; 559 data->expect_prefer_cores.clusters = 1; 560 } 561 } 562 563 static void machine_base_class_init(ObjectClass *oc, void *data) 564 { 565 MachineClass *mc = MACHINE_CLASS(oc); 566 567 mc->min_cpus = MIN_CPUS; 568 mc->max_cpus = MAX_CPUS; 569 570 mc->name = g_strdup(SMP_MACHINE_NAME); 571 } 572 573 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) 574 { 575 MachineClass *mc = MACHINE_CLASS(oc); 576 577 /* Force invalid min CPUs and max CPUs */ 578 mc->min_cpus = 2; 579 mc->max_cpus = 511; 580 } 581 582 static void machine_with_dies_class_init(ObjectClass *oc, void *data) 583 { 584 MachineClass *mc = MACHINE_CLASS(oc); 585 586 mc->smp_props.dies_supported = true; 587 } 588 589 static void machine_with_clusters_class_init(ObjectClass *oc, void *data) 590 { 591 MachineClass *mc = MACHINE_CLASS(oc); 592 593 mc->smp_props.clusters_supported = true; 594 } 595 596 static void test_generic_valid(const void *opaque) 597 { 598 const char *machine_type = opaque; 599 Object *obj = object_new(machine_type); 600 MachineState *ms = MACHINE(obj); 601 MachineClass *mc = MACHINE_GET_CLASS(obj); 602 SMPTestData data = {}; 603 int i; 604 605 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 606 data = data_generic_valid[i]; 607 unsupported_params_init(mc, &data); 608 609 smp_parse_test(ms, &data, true); 610 611 /* Unsupported parameters can be provided with their values as 1 */ 612 data.config.has_dies = true; 613 data.config.dies = 1; 614 smp_parse_test(ms, &data, true); 615 } 616 617 object_unref(obj); 618 } 619 620 static void test_generic_invalid(const void *opaque) 621 { 622 const char *machine_type = opaque; 623 Object *obj = object_new(machine_type); 624 MachineState *ms = MACHINE(obj); 625 MachineClass *mc = MACHINE_GET_CLASS(obj); 626 SMPTestData data = {}; 627 int i; 628 629 for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) { 630 data = data_generic_invalid[i]; 631 unsupported_params_init(mc, &data); 632 633 smp_parse_test(ms, &data, false); 634 } 635 636 object_unref(obj); 637 } 638 639 static void test_with_dies(const void *opaque) 640 { 641 const char *machine_type = opaque; 642 Object *obj = object_new(machine_type); 643 MachineState *ms = MACHINE(obj); 644 MachineClass *mc = MACHINE_GET_CLASS(obj); 645 SMPTestData data = {}; 646 unsigned int num_dies = 2; 647 int i; 648 649 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 650 data = data_generic_valid[i]; 651 unsupported_params_init(mc, &data); 652 653 /* when dies parameter is omitted, it will be set as 1 */ 654 data.expect_prefer_sockets.dies = 1; 655 data.expect_prefer_cores.dies = 1; 656 657 smp_parse_test(ms, &data, true); 658 659 /* when dies parameter is specified */ 660 data.config.has_dies = true; 661 data.config.dies = num_dies; 662 if (data.config.has_cpus) { 663 data.config.cpus *= num_dies; 664 } 665 if (data.config.has_maxcpus) { 666 data.config.maxcpus *= num_dies; 667 } 668 669 data.expect_prefer_sockets.dies = num_dies; 670 data.expect_prefer_sockets.cpus *= num_dies; 671 data.expect_prefer_sockets.max_cpus *= num_dies; 672 data.expect_prefer_cores.dies = num_dies; 673 data.expect_prefer_cores.cpus *= num_dies; 674 data.expect_prefer_cores.max_cpus *= num_dies; 675 676 smp_parse_test(ms, &data, true); 677 } 678 679 for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { 680 data = data_with_dies_invalid[i]; 681 unsupported_params_init(mc, &data); 682 683 smp_parse_test(ms, &data, false); 684 } 685 686 object_unref(obj); 687 } 688 689 static void test_with_clusters(const void *opaque) 690 { 691 const char *machine_type = opaque; 692 Object *obj = object_new(machine_type); 693 MachineState *ms = MACHINE(obj); 694 MachineClass *mc = MACHINE_GET_CLASS(obj); 695 SMPTestData data = {}; 696 unsigned int num_clusters = 2; 697 int i; 698 699 for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) { 700 data = data_generic_valid[i]; 701 unsupported_params_init(mc, &data); 702 703 /* when clusters parameter is omitted, it will be set as 1 */ 704 data.expect_prefer_sockets.clusters = 1; 705 data.expect_prefer_cores.clusters = 1; 706 707 smp_parse_test(ms, &data, true); 708 709 /* when clusters parameter is specified */ 710 data.config.has_clusters = true; 711 data.config.clusters = num_clusters; 712 if (data.config.has_cpus) { 713 data.config.cpus *= num_clusters; 714 } 715 if (data.config.has_maxcpus) { 716 data.config.maxcpus *= num_clusters; 717 } 718 719 data.expect_prefer_sockets.clusters = num_clusters; 720 data.expect_prefer_sockets.cpus *= num_clusters; 721 data.expect_prefer_sockets.max_cpus *= num_clusters; 722 data.expect_prefer_cores.clusters = num_clusters; 723 data.expect_prefer_cores.cpus *= num_clusters; 724 data.expect_prefer_cores.max_cpus *= num_clusters; 725 726 smp_parse_test(ms, &data, true); 727 } 728 729 for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) { 730 data = data_with_clusters_invalid[i]; 731 unsupported_params_init(mc, &data); 732 733 smp_parse_test(ms, &data, false); 734 } 735 736 object_unref(obj); 737 } 738 739 /* Type info of the tested machine */ 740 static const TypeInfo smp_machine_types[] = { 741 { 742 .name = TYPE_MACHINE, 743 .parent = TYPE_OBJECT, 744 .abstract = true, 745 .class_init = machine_base_class_init, 746 .class_size = sizeof(MachineClass), 747 .instance_size = sizeof(MachineState), 748 }, { 749 .name = MACHINE_TYPE_NAME("smp-generic-valid"), 750 .parent = TYPE_MACHINE, 751 }, { 752 .name = MACHINE_TYPE_NAME("smp-generic-invalid"), 753 .parent = TYPE_MACHINE, 754 .class_init = machine_generic_invalid_class_init, 755 }, { 756 .name = MACHINE_TYPE_NAME("smp-with-dies"), 757 .parent = TYPE_MACHINE, 758 .class_init = machine_with_dies_class_init, 759 }, { 760 .name = MACHINE_TYPE_NAME("smp-with-clusters"), 761 .parent = TYPE_MACHINE, 762 .class_init = machine_with_clusters_class_init, 763 } 764 }; 765 766 DEFINE_TYPES(smp_machine_types) 767 768 int main(int argc, char *argv[]) 769 { 770 module_call_init(MODULE_INIT_QOM); 771 772 g_test_init(&argc, &argv, NULL); 773 774 g_test_add_data_func("/test-smp-parse/generic/valid", 775 MACHINE_TYPE_NAME("smp-generic-valid"), 776 test_generic_valid); 777 g_test_add_data_func("/test-smp-parse/generic/invalid", 778 MACHINE_TYPE_NAME("smp-generic-invalid"), 779 test_generic_invalid); 780 g_test_add_data_func("/test-smp-parse/with_dies", 781 MACHINE_TYPE_NAME("smp-with-dies"), 782 test_with_dies); 783 g_test_add_data_func("/test-smp-parse/with_clusters", 784 MACHINE_TYPE_NAME("smp-with-clusters"), 785 test_with_clusters); 786 787 g_test_run(); 788 789 return 0; 790 } 791