From nobody Mon Feb 9 14:38:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=philmd@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=philmd@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1635792220; cv=none; d=zohomail.com; s=zohoarc; b=fCjOKwKQoTNNpmxqkgPNBXIYrDmQ2BiYC1n9pHIC+DfoJw05GoD4wRElPRn+KPmfcAqVC1d5ACS3FkNpR8N6L+Q3hJUevm7NoCXyGT5rlcq61bP5JQOcpkgZVyrz79q3v2HCYOKgv6nyngjhJWFgsBpli+5QWwk+t2/e11/a3x8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1635792220; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=/h0darTf513WPkfexGnPhY2VjdovSQxyXVgcl2pMqi8=; b=bw4qOcvBAZ5WriHPRmIrNEMo2IvL8C7vxQ4GxA2xmZqTAPn8wrw6PXIQG8p5OPiA/aKErrlDbZjKxjxULY+c0yd7QBku3yyOHKeliKFV1Akz82ss8TRBnHoxaWpFSZPfKyOv1h14Qf8fgi3I/eIAvVGdS4EEJBtSx3Q/u5tMOsI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=philmd@redhat.com; dmarc=pass header.from= (p=none dis=none) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1635792220469625.6026532648086; Mon, 1 Nov 2021 11:43:40 -0700 (PDT) Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-596-V-s91zLfPvSKoB6ao5kYYw-1; Mon, 01 Nov 2021 14:43:38 -0400 Received: by mail-wm1-f70.google.com with SMTP id m1-20020a1ca301000000b003231d5b3c4cso50420wme.5 for ; Mon, 01 Nov 2021 11:43:37 -0700 (PDT) Return-Path: Return-Path: Received: from x1w.. (62.red-83-57-168.dynamicip.rima-tde.net. [83.57.168.62]) by smtp.gmail.com with ESMTPSA id 10sm345396wme.27.2021.11.01.11.43.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Nov 2021 11:43:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1635792219; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/h0darTf513WPkfexGnPhY2VjdovSQxyXVgcl2pMqi8=; b=UgP61SIvLWjAmdLyqs3Zfh7fly9IfsnJZI27oWaSHL0voA4D1Spfj0Oc+U+Yo923BD37x5 g3ysFK47gPPB5PsH3tx5nP4ycWQay3XE6+A7EIxgoNJ89Owm9gGcg3oVZnVXFa9c7X5eG1 nulc9OVI59NGI030+nX2HGYcDsEtTpU= X-MC-Unique: V-s91zLfPvSKoB6ao5kYYw-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/h0darTf513WPkfexGnPhY2VjdovSQxyXVgcl2pMqi8=; b=TTJu2NDv41x0iGbb2OCjoZiaBlvhGepbbeyf72znIfvlIgB2vAWH0AS3FPybSAOAlr hzn0Z7Sf/MDVbd6SB2rNOmcVCUks8TqfPJ7CNT5mtugzwHMPVaSH3DM0F2QEmm/508fG 08FFj2fQLUSwFPrf3ie/cAdIbVpFK38Dmw+7xfueGIcCR0hakWbtSr0NepAFaZgek5jC R41NRKiedOxPgmtDG1UyDdjW7CODVPX/xkx3Yh0ZPBCQosYO9ftyi0DrHeAgTIhY8od+ kovz/D7PqB71BVtZRUsKQbe2S9CXZiF4khilytr590KeyYmTNGtMnJu77kTT/UKnKGnU /kqg== X-Gm-Message-State: AOAM532OHk9c3AB309uymnf84fEmSLQdtkpdPZYYToOqNt6ELpvnLDCm S0EhEVFzpIvy6mqQIP6u/CVtf7Rm7a5brQYxTKwtBEOPOyqARmQjt+TguSbgpoO38BcqD1A5X0o MrrCm++Cybf7XQg== X-Received: by 2002:a05:600c:1d06:: with SMTP id l6mr716026wms.97.1635792216402; Mon, 01 Nov 2021 11:43:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJztdU5aHWPvsJkmmBuSl7DVTF1SEzIfJiA035/X8zBrReugZT3oLcZkXpv17/DxDraPnR0+JA== X-Received: by 2002:a05:600c:1d06:: with SMTP id l6mr715981wms.97.1635792216067; Mon, 01 Nov 2021 11:43:36 -0700 (PDT) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Cc: Eduardo Habkost , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcel Apfelbaum , Yanan Wang , Andrew Jones Subject: [PULL 07/10] tests/unit: Add an unit test for smp parsing Date: Mon, 1 Nov 2021 19:42:56 +0100 Message-Id: <20211101184259.2859090-8-philmd@redhat.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211101184259.2859090-1-philmd@redhat.com> References: <20211101184259.2859090-1-philmd@redhat.com> MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=philmd@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1635792221348100001 From: Yanan Wang Now that we have a generic parser smp_parse(), let's add an unit test for the code. All possible valid/invalid SMP configurations that the user can specify are covered. Signed-off-by: Yanan Wang Reviewed-by: Andrew Jones Tested-by: Philippe Mathieu-Daud=C3=A9 Message-Id: <20211026034659.22040-3-wangyanan55@huawei.com> Acked-by: Eduardo Habkost Message-Id: [PMD: Squashed format string fixup from Yanan Wang] Signed-off-by: Philippe Mathieu-Daud=C3=A9 --- tests/unit/test-smp-parse.c | 594 ++++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + tests/unit/meson.build | 1 + 3 files changed, 596 insertions(+) create mode 100644 tests/unit/test-smp-parse.c diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c new file mode 100644 index 00000000000..cbe0c990494 --- /dev/null +++ b/tests/unit/test-smp-parse.c @@ -0,0 +1,594 @@ +/* + * SMP parsing unit-tests + * + * Copyright (c) 2021 Huawei Technologies Co., Ltd + * + * Authors: + * Yanan Wang + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or l= ater. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qom/object.h" +#include "qemu/module.h" +#include "qapi/error.h" + +#include "hw/boards.h" + +#define T true +#define F false + +#define MIN_CPUS 1 /* set the min CPUs supported by the machine as 1 */ +#define MAX_CPUS 512 /* set the max CPUs supported by the machine as 512 */ + +/* + * Used to define the generic 3-level CPU topology hierarchy + * -sockets/cores/threads + */ +#define SMP_CONFIG_GENERIC(ha, a, hb, b, hc, c, hd, d, he, e) \ + { \ + .has_cpus =3D ha, .cpus =3D a, \ + .has_sockets =3D hb, .sockets =3D b, \ + .has_cores =3D hc, .cores =3D c, \ + .has_threads =3D hd, .threads =3D d, \ + .has_maxcpus =3D he, .maxcpus =3D e, \ + } + +#define CPU_TOPOLOGY_GENERIC(a, b, c, d, e) \ + { \ + .cpus =3D a, \ + .sockets =3D b, \ + .cores =3D c, \ + .threads =3D d, \ + .max_cpus =3D e, \ + } + +/* + * Currently a 4-level topology hierarchy is supported on PC machines + * -sockets/dies/cores/threads + */ +#define SMP_CONFIG_WITH_DIES(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \ + { \ + .has_cpus =3D ha, .cpus =3D a, \ + .has_sockets =3D hb, .sockets =3D b, \ + .has_dies =3D hc, .dies =3D c, \ + .has_cores =3D hd, .cores =3D d, \ + .has_threads =3D he, .threads =3D e, \ + .has_maxcpus =3D hf, .maxcpus =3D f, \ + } + +/** + * @config - the given SMP configuration + * @expect_prefer_sockets - the expected parsing result for the + * valid configuration, when sockets are preferred over cores + * @expect_prefer_cores - the expected parsing result for the + * valid configuration, when cores are preferred over sockets + * @expect_error - the expected error report when the given + * configuration is invalid + */ +typedef struct SMPTestData { + SMPConfiguration config; + CpuTopology expect_prefer_sockets; + CpuTopology expect_prefer_cores; + const char *expect_error; +} SMPTestData; + +/* Type info of the tested machine */ +static const TypeInfo smp_machine_info =3D { + .name =3D TYPE_MACHINE, + .parent =3D TYPE_OBJECT, + .class_size =3D sizeof(MachineClass), + .instance_size =3D sizeof(MachineState), +}; + +/* + * List all the possible valid sub-collections of the generic 5 + * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads), + * then test the automatic calculation algorithm of the missing + * values in the parser. + */ +static struct SMPTestData data_generic_valid[] =3D { + { + /* config: no configuration provided + * expect: cpus=3D1,sockets=3D1,cores=3D1,threads=3D1,maxcpus=3D1 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1), + }, { + /* config: -smp 8 + * prefer_sockets: cpus=3D8,sockets=3D8,cores=3D1,threads=3D1,maxc= pus=3D8 + * prefer_cores: cpus=3D8,sockets=3D1,cores=3D8,threads=3D1,maxcpu= s=3D8 */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8), + }, { + /* config: -smp sockets=3D2 + * expect: cpus=3D2,sockets=3D2,cores=3D1,threads=3D1,maxcpus=3D2 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2), + }, { + /* config: -smp cores=3D4 + * expect: cpus=3D4,sockets=3D1,cores=3D4,threads=3D1,maxcpus=3D4 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4), + }, { + /* config: -smp threads=3D2 + * expect: cpus=3D2,sockets=3D1,cores=3D1,threads=3D2,maxcpus=3D2 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2), + }, { + /* config: -smp maxcpus=3D16 + * prefer_sockets: cpus=3D16,sockets=3D16,cores=3D1,threads=3D1,ma= xcpus=3D16 + * prefer_cores: cpus=3D16,sockets=3D1,cores=3D16,threads=3D1,maxc= pus=3D16 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16), + }, { + /* config: -smp 8,sockets=3D2 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D1,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,cores=3D4 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D1,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,threads=3D2 + * prefer_sockets: cpus=3D8,sockets=3D4,cores=3D1,threads=3D2,maxc= pus=3D8 + * prefer_cores: cpus=3D8,sockets=3D1,cores=3D4,threads=3D2,maxcpu= s=3D8 */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp 8,maxcpus=3D16 + * prefer_sockets: cpus=3D8,sockets=3D16,cores=3D1,threads=3D1,max= cpus=3D16 + * prefer_cores: cpus=3D8,sockets=3D1,cores=3D16,threads=3D1,maxcp= us=3D16 */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16), + }, { + /* config: -smp sockets=3D2,cores=3D4 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D1,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp sockets=3D2,threads=3D2 + * expect: cpus=3D4,sockets=3D2,cores=3D1,threads=3D2,maxcpus=3D4 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4), + }, { + /* config: -smp sockets=3D2,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D2,cores=3D8,threads=3D1,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16), + }, { + /* config: -smp cores=3D4,threads=3D2 + * expect: cpus=3D8,sockets=3D1,cores=3D4,threads=3D2,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp cores=3D4,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D4,cores=3D4,threads=3D1,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16), + }, { + /* config: -smp threads=3D2,maxcpus=3D16 + * prefer_sockets: cpus=3D16,sockets=3D8,cores=3D1,threads=3D2,max= cpus=3D16 + * prefer_cores: cpus=3D16,sockets=3D1,cores=3D8,threads=3D2,maxcp= us=3D16 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16), + }, { + /* config: -smp 8,sockets=3D2,cores=3D4 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D1,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,sockets=3D2,threads=3D2 + * expect: cpus=3D8,sockets=3D2,cores=3D2,threads=3D2,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8), + }, { + /* config: -smp 8,sockets=3D2,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D2,cores=3D8,threads=3D1,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16), + }, { + /* config: -smp 8,cores=3D4,threads=3D2 + * expect: cpus=3D8,sockets=3D1,cores=3D4,threads=3D2,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8), + }, { + /* config: -smp 8,cores=3D4,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D4,cores=3D4,threads=3D1,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16), + }, { + /* config: -smp 8,threads=3D2,maxcpus=3D16 + * prefer_sockets: cpus=3D8,sockets=3D8,cores=3D1,threads=3D2,maxc= pus=3D16 + * prefer_cores: cpus=3D8,sockets=3D1,cores=3D8,threads=3D2,maxcpu= s=3D16 */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16), + }, { + /* config: -smp sockets=3D2,cores=3D4,threads=3D2 + * expect: cpus=3D16,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp sockets=3D2,cores=3D4,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp sockets=3D2,threads=3D2,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp cores=3D4,threads=3D2,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=3D2,cores=3D4,threads=3D1 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D1,maxcpus=3D8 = */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8), + }, { + /* config: -smp 8,sockets=3D2,cores=3D4,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=3D2,threads=3D2,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp 8,cores=3D4,threads=3D2,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, { + /* config: -smp sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16 + * expect: cpus=3D16,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D1= 6 */ + .config =3D SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16), + }, { + /* config: -smp 8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16 + * expect: cpus=3D8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16= */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16), + .expect_prefer_sockets =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + .expect_prefer_cores =3D CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16), + }, +}; + +static struct SMPTestData data_generic_invalid[] =3D { + { + /* config: -smp 2,dies=3D2 */ + .config =3D SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, = 0), + .expect_error =3D "dies not supported by this machine's CPU topolo= gy", + }, { + /* config: -smp 8,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D8 */ + .config =3D SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8), + .expect_error =3D "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " + "sockets (2) * cores (4) * threads (2) " + "!=3D maxcpus (8)", + }, { + /* config: -smp 18,sockets=3D2,cores=3D4,threads=3D2,maxcpus=3D16 = */ + .config =3D SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16), + .expect_error =3D "Invalid CPU topology: " + "maxcpus must be equal to or greater than smp: " + "sockets (2) * cores (4) * threads (2) " + "=3D=3D maxcpus (16) < smp_cpus (18)", + }, { + /* config: -smp 1 + * should tweak the supported min CPUs to 2 for testing */ + .config =3D SMP_CONFIG_GENERIC(T, 1, F, 0, F, 0, F, 0, F, 0), + .expect_error =3D "Invalid SMP CPUs 1. The min CPUs supported " + "by machine '(null)' is 2", + }, { + /* config: -smp 512 + * should tweak the supported max CPUs to 511 for testing */ + .config =3D SMP_CONFIG_GENERIC(T, 512, F, 0, F, 0, F, 0, F, 0), + .expect_error =3D "Invalid SMP CPUs 512. The max CPUs supported " + "by machine '(null)' is 511", + }, +}; + +static struct SMPTestData data_with_dies_invalid[] =3D { + { + /* config: -smp 16,sockets=3D2,dies=3D2,cores=3D4,threads=3D2,maxc= pus=3D16 */ + .config =3D SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T,= 16), + .expect_error =3D "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " + "sockets (2) * dies (2) * cores (4) * threads (2) " + "!=3D maxcpus (16)", + }, { + /* config: -smp 34,sockets=3D2,dies=3D2,cores=3D4,threads=3D2,maxc= pus=3D32 */ + .config =3D SMP_CONFIG_WITH_DIES(T, 34, T, 2, T, 2, T, 4, T, 2, T,= 32), + .expect_error =3D "Invalid CPU topology: " + "maxcpus must be equal to or greater than smp: " + "sockets (2) * dies (2) * cores (4) * threads (2) " + "=3D=3D maxcpus (32) < smp_cpus (34)", + }, +}; + +static char *smp_config_to_string(SMPConfiguration *config) +{ + return g_strdup_printf( + "(SMPConfiguration) {\n" + " .has_cpus =3D %5s, cpus =3D %" PRId64 ",\n" + " .has_sockets =3D %5s, sockets =3D %" PRId64 ",\n" + " .has_dies =3D %5s, dies =3D %" PRId64 ",\n" + " .has_cores =3D %5s, cores =3D %" PRId64 ",\n" + " .has_threads =3D %5s, threads =3D %" PRId64 ",\n" + " .has_maxcpus =3D %5s, maxcpus =3D %" PRId64 ",\n" + "}", + config->has_cpus ? "true" : "false", config->cpus, + config->has_sockets ? "true" : "false", config->sockets, + config->has_dies ? "true" : "false", config->dies, + config->has_cores ? "true" : "false", config->cores, + config->has_threads ? "true" : "false", config->threads, + config->has_maxcpus ? "true" : "false", config->maxcpus); +} + +static char *cpu_topology_to_string(CpuTopology *topo) +{ + return g_strdup_printf( + "(CpuTopology) {\n" + " .cpus =3D %u,\n" + " .sockets =3D %u,\n" + " .dies =3D %u,\n" + " .cores =3D %u,\n" + " .threads =3D %u,\n" + " .max_cpus =3D %u,\n" + "}", + topo->cpus, topo->sockets, topo->dies, + topo->cores, topo->threads, topo->max_cpus); +} + +static void check_parse(MachineState *ms, SMPConfiguration *config, + CpuTopology *expect_topo, const char *expect_err, + bool is_valid) +{ + g_autofree char *config_str =3D smp_config_to_string(config); + g_autofree char *expect_topo_str =3D cpu_topology_to_string(expect_top= o); + g_autofree char *output_topo_str =3D NULL; + Error *err =3D NULL; + + /* call the generic parser smp_parse() */ + smp_parse(ms, config, &err); + + output_topo_str =3D cpu_topology_to_string(&ms->smp); + + /* when the configuration is supposed to be valid */ + if (is_valid) { + if ((err =3D=3D NULL) && + (ms->smp.cpus =3D=3D expect_topo->cpus) && + (ms->smp.sockets =3D=3D expect_topo->sockets) && + (ms->smp.dies =3D=3D expect_topo->dies) && + (ms->smp.cores =3D=3D expect_topo->cores) && + (ms->smp.threads =3D=3D expect_topo->threads) && + (ms->smp.max_cpus =3D=3D expect_topo->max_cpus)) { + return; + } + + if (err !=3D NULL) { + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: yes\n" + "Expected topology: %s\n\n" + "Result is valid: no\n" + "Output error report: %s\n", + config_str, expect_topo_str, error_get_pretty(err)); + goto end; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: yes\n" + "Expected topology: %s\n\n" + "Result is valid: yes\n" + "Output topology: %s\n", + config_str, expect_topo_str, output_topo_str); + goto end; + } + + /* when the configuration is supposed to be invalid */ + if (err !=3D NULL) { + if (expect_err =3D=3D NULL || + g_str_equal(expect_err, error_get_pretty(err))) { + error_free(err); + return; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: no\n" + "Expected error report: %s\n\n" + "Result is valid: no\n" + "Output error report: %s\n", + config_str, expect_err, error_get_pretty(err)); + goto end; + } + + g_printerr("Test smp_parse failed!\n" + "Input configuration: %s\n" + "Should be valid: no\n" + "Expected error report: %s\n\n" + "Result is valid: yes\n" + "Output topology: %s\n", + config_str, expect_err, output_topo_str); + +end: + if (err !=3D NULL) { + error_free(err); + } + + abort(); +} + +static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_va= lid) +{ + MachineClass *mc =3D MACHINE_GET_CLASS(ms); + + mc->smp_props.prefer_sockets =3D true; + check_parse(ms, &data->config, &data->expect_prefer_sockets, + data->expect_error, is_valid); + + mc->smp_props.prefer_sockets =3D false; + check_parse(ms, &data->config, &data->expect_prefer_cores, + data->expect_error, is_valid); +} + +/* The parsed results of the unsupported parameters should be 1 */ +static void unsupported_params_init(MachineClass *mc, SMPTestData *data) +{ + if (!mc->smp_props.dies_supported) { + data->expect_prefer_sockets.dies =3D 1; + data->expect_prefer_cores.dies =3D 1; + } +} + +/* Reset the related machine properties before each sub-test */ +static void smp_machine_class_init(MachineClass *mc) +{ + mc->min_cpus =3D MIN_CPUS; + mc->max_cpus =3D MAX_CPUS; + + mc->smp_props.prefer_sockets =3D true; + mc->smp_props.dies_supported =3D false; +} + +static void test_generic(void) +{ + Object *obj =3D object_new(TYPE_MACHINE); + MachineState *ms =3D MACHINE(obj); + MachineClass *mc =3D MACHINE_GET_CLASS(obj); + SMPTestData *data =3D &(SMPTestData){{ }}; + int i; + + smp_machine_class_init(mc); + + for (i =3D 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data =3D data_generic_valid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, true); + + /* Unsupported parameters can be provided with their values as 1 */ + data->config.has_dies =3D true; + data->config.dies =3D 1; + smp_parse_test(ms, data, true); + } + + /* Reset the supported min CPUs and max CPUs */ + mc->min_cpus =3D 2; + mc->max_cpus =3D 511; + + for (i =3D 0; i < ARRAY_SIZE(data_generic_invalid); i++) { + *data =3D data_generic_invalid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, false); + } + + object_unref(obj); +} + +static void test_with_dies(void) +{ + Object *obj =3D object_new(TYPE_MACHINE); + MachineState *ms =3D MACHINE(obj); + MachineClass *mc =3D MACHINE_GET_CLASS(obj); + SMPTestData *data =3D &(SMPTestData){{ }}; + unsigned int num_dies =3D 2; + int i; + + smp_machine_class_init(mc); + mc->smp_props.dies_supported =3D true; + + for (i =3D 0; i < ARRAY_SIZE(data_generic_valid); i++) { + *data =3D data_generic_valid[i]; + unsupported_params_init(mc, data); + + /* when dies parameter is omitted, it will be set as 1 */ + data->expect_prefer_sockets.dies =3D 1; + data->expect_prefer_cores.dies =3D 1; + + smp_parse_test(ms, data, true); + + /* when dies parameter is specified */ + data->config.has_dies =3D true; + data->config.dies =3D num_dies; + if (data->config.has_cpus) { + data->config.cpus *=3D num_dies; + } + if (data->config.has_maxcpus) { + data->config.maxcpus *=3D num_dies; + } + + data->expect_prefer_sockets.dies =3D num_dies; + data->expect_prefer_sockets.cpus *=3D num_dies; + data->expect_prefer_sockets.max_cpus *=3D num_dies; + data->expect_prefer_cores.dies =3D num_dies; + data->expect_prefer_cores.cpus *=3D num_dies; + data->expect_prefer_cores.max_cpus *=3D num_dies; + + smp_parse_test(ms, data, true); + } + + for (i =3D 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) { + *data =3D data_with_dies_invalid[i]; + unsupported_params_init(mc, data); + + smp_parse_test(ms, data, false); + } + + object_unref(obj); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + type_register_static(&smp_machine_info); + + g_test_add_func("/test-smp-parse/generic", test_generic); + g_test_add_func("/test-smp-parse/with_dies", test_with_dies); + + g_test_run(); + + return 0; +} diff --git a/MAINTAINERS b/MAINTAINERS index 80ec27d76ae..310a9512ea1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1633,6 +1633,7 @@ F: include/hw/boards.h F: include/hw/core/cpu.h F: include/hw/cpu/cluster.h F: include/sysemu/numa.h +F: tests/unit/test-smp-parse.c T: git https://gitlab.com/ehabkost/qemu.git machine-next =20 Xtensa Machines diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 5ac2d9e9431..acac3622edc 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -46,6 +46,7 @@ 'test-uuid': [], 'ptimer-test': ['ptimer-test-stubs.c', meson.project_source_root() / 'hw= /core/ptimer.c'], 'test-qapi-util': [], + 'test-smp-parse': [qom, meson.project_source_root() / 'hw/core/machine-s= mp.c'], } =20 if have_system or have_tools --=20 2.31.1