qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-smp-parse.c (30669B)


      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 }