From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 3A68F1FF145 for ; Thu, 05 Feb 2026 15:19:34 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0693012145; Thu, 5 Feb 2026 15:20:05 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server v3 2/3] tests: improve multiarch build support by allowing re-init of cpu models Date: Thu, 5 Feb 2026 15:17:12 +0100 Message-ID: <20260205141959.3615131-3-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260205141959.3615131-1-d.csapak@proxmox.com> References: <20260205141959.3615131-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.031 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: UYC5JSX3EN2CSEOPO26V6SY3JANPP2MN X-Message-ID-Hash: UYC5JSX3EN2CSEOPO26V6SY3JANPP2MN X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: instead of simply saving 'host_arch','all_cpu_models' and 'cpu_models_by_arch' in the global package namespace, after initializing directly in the module, use an initialization function and a getter to generate this. This has two advantages: * Only the first use actually fills the package wide variable (currently the $cpu_fmt uses this on module load) * We can call the initialization manually in the tests where we need it Signed-off-by: Dominik Csapak --- changes from v2: * split out from first patch * use getters that auto-initialize the global cpu model list src/PVE/QemuServer/CPUConfig.pm | 272 ++++++++++++++------------- src/test/run_config2command_tests.pl | 2 + 2 files changed, 148 insertions(+), 126 deletions(-) diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm index 0218908e..165c48a7 100644 --- a/src/PVE/QemuServer/CPUConfig.pm +++ b/src/PVE/QemuServer/CPUConfig.pm @@ -25,8 +25,6 @@ our @EXPORT_OK = qw( get_cvm_type ); -my $host_arch = get_host_arch(); - my $arch_desc = { description => "Virtual processor architecture. Defaults to the host architecture.", type => 'string', @@ -100,130 +98,152 @@ my $cputypes_32bit = { 'qemu32' => 1, }; -my $cpu_models_by_arch = { - x86_64 => { - # Intel CPUs - 486 => 'GenuineIntel', - pentium => 'GenuineIntel', - pentium2 => 'GenuineIntel', - pentium3 => 'GenuineIntel', - coreduo => 'GenuineIntel', - core2duo => 'GenuineIntel', - Conroe => 'GenuineIntel', - Penryn => 'GenuineIntel', - Nehalem => 'GenuineIntel', - 'Nehalem-IBRS' => 'GenuineIntel', - Westmere => 'GenuineIntel', - 'Westmere-IBRS' => 'GenuineIntel', - SandyBridge => 'GenuineIntel', - 'SandyBridge-IBRS' => 'GenuineIntel', - IvyBridge => 'GenuineIntel', - 'IvyBridge-IBRS' => 'GenuineIntel', - Haswell => 'GenuineIntel', - 'Haswell-IBRS' => 'GenuineIntel', - 'Haswell-noTSX' => 'GenuineIntel', - 'Haswell-noTSX-IBRS' => 'GenuineIntel', - Broadwell => 'GenuineIntel', - 'Broadwell-IBRS' => 'GenuineIntel', - 'Broadwell-noTSX' => 'GenuineIntel', - 'Broadwell-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Client' => 'GenuineIntel', - 'Skylake-Client-IBRS' => 'GenuineIntel', - 'Skylake-Client-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Client-v4' => 'GenuineIntel', - 'Skylake-Server' => 'GenuineIntel', - 'Skylake-Server-IBRS' => 'GenuineIntel', - 'Skylake-Server-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Server-v4' => 'GenuineIntel', - 'Skylake-Server-v5' => 'GenuineIntel', - 'Cascadelake-Server' => 'GenuineIntel', - 'Cascadelake-Server-v2' => 'GenuineIntel', - 'Cascadelake-Server-noTSX' => 'GenuineIntel', - 'Cascadelake-Server-v4' => 'GenuineIntel', - 'Cascadelake-Server-v5' => 'GenuineIntel', - 'Cooperlake' => 'GenuineIntel', - 'Cooperlake-v2' => 'GenuineIntel', - KnightsMill => 'GenuineIntel', - 'Icelake-Client' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 - 'Icelake-Client-noTSX' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 - 'Icelake-Server' => 'GenuineIntel', - 'Icelake-Server-noTSX' => 'GenuineIntel', - 'Icelake-Server-v3' => 'GenuineIntel', - 'Icelake-Server-v4' => 'GenuineIntel', - 'Icelake-Server-v5' => 'GenuineIntel', - 'Icelake-Server-v6' => 'GenuineIntel', - 'Icelake-Server-v7' => 'GenuineIntel', - 'SapphireRapids' => 'GenuineIntel', - 'SapphireRapids-v2' => 'GenuineIntel', - 'SapphireRapids-v3' => 'GenuineIntel', - 'SapphireRapids-v4' => 'GenuineIntel', - 'GraniteRapids' => 'GenuineIntel', - 'GraniteRapids-v2' => 'GenuineIntel', - 'GraniteRapids-v3' => 'GenuineIntel', - 'SierraForest' => 'GenuineIntel', - 'SierraForest-v2' => 'GenuineIntel', - 'SierraForest-v3' => 'GenuineIntel', - 'ClearwaterForest' => 'GenuineIntel', - - # AMD CPUs - athlon => 'AuthenticAMD', - phenom => 'AuthenticAMD', - Opteron_G1 => 'AuthenticAMD', - Opteron_G2 => 'AuthenticAMD', - Opteron_G3 => 'AuthenticAMD', - Opteron_G4 => 'AuthenticAMD', - Opteron_G5 => 'AuthenticAMD', - EPYC => 'AuthenticAMD', - 'EPYC-IBPB' => 'AuthenticAMD', - 'EPYC-v3' => 'AuthenticAMD', - 'EPYC-v4' => 'AuthenticAMD', - 'EPYC-v5' => 'AuthenticAMD', - 'EPYC-Rome' => 'AuthenticAMD', - 'EPYC-Rome-v2' => 'AuthenticAMD', - 'EPYC-Rome-v3' => 'AuthenticAMD', - 'EPYC-Rome-v4' => 'AuthenticAMD', - 'EPYC-Rome-v5' => 'AuthenticAMD', - 'EPYC-Milan' => 'AuthenticAMD', - 'EPYC-Milan-v2' => 'AuthenticAMD', - 'EPYC-Milan-v3' => 'AuthenticAMD', - 'EPYC-Genoa' => 'AuthenticAMD', - 'EPYC-Genoa-v2' => 'AuthenticAMD', - 'EPYC-Turin' => 'AuthenticAMD', - - # generic types, use vendor from host node - kvm32 => 'default', - kvm64 => 'default', - qemu32 => 'default', - qemu64 => 'default', - max => 'default', - }, - aarch64 => { - 'a64fx' => 'ARM', - 'cortex-a35' => 'ARM', - 'cortex-a53' => 'ARM', - 'cortex-a55' => 'ARM', - 'cortex-a57' => 'ARM', - 'cortex-a710' => 'ARM', - 'cortex-a72' => 'ARM', - 'cortex-a76' => 'ARM', - 'neoverse-n1' => 'ARM', - 'neoverse-n2' => 'ARM', - 'neoverse-v1' => 'ARM', - # 32 bit and deprecated models were not added - max => 'default', - }, -}; +my $cpu_models_by_arch; +my $all_cpu_models; -# The host CPU model only exists if the arch matches -$cpu_models_by_arch->{$host_arch}->{host} = 'default'; +# helper to make it easier for testing +# initializes both '$cpu_models_by_arch' and '$all_cpu_models' +sub initialize_cpu_models { + $cpu_models_by_arch = { + x86_64 => { + # Intel CPUs + 486 => 'GenuineIntel', + pentium => 'GenuineIntel', + pentium2 => 'GenuineIntel', + pentium3 => 'GenuineIntel', + coreduo => 'GenuineIntel', + core2duo => 'GenuineIntel', + Conroe => 'GenuineIntel', + Penryn => 'GenuineIntel', + Nehalem => 'GenuineIntel', + 'Nehalem-IBRS' => 'GenuineIntel', + Westmere => 'GenuineIntel', + 'Westmere-IBRS' => 'GenuineIntel', + SandyBridge => 'GenuineIntel', + 'SandyBridge-IBRS' => 'GenuineIntel', + IvyBridge => 'GenuineIntel', + 'IvyBridge-IBRS' => 'GenuineIntel', + Haswell => 'GenuineIntel', + 'Haswell-IBRS' => 'GenuineIntel', + 'Haswell-noTSX' => 'GenuineIntel', + 'Haswell-noTSX-IBRS' => 'GenuineIntel', + Broadwell => 'GenuineIntel', + 'Broadwell-IBRS' => 'GenuineIntel', + 'Broadwell-noTSX' => 'GenuineIntel', + 'Broadwell-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Client' => 'GenuineIntel', + 'Skylake-Client-IBRS' => 'GenuineIntel', + 'Skylake-Client-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Client-v4' => 'GenuineIntel', + 'Skylake-Server' => 'GenuineIntel', + 'Skylake-Server-IBRS' => 'GenuineIntel', + 'Skylake-Server-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Server-v4' => 'GenuineIntel', + 'Skylake-Server-v5' => 'GenuineIntel', + 'Cascadelake-Server' => 'GenuineIntel', + 'Cascadelake-Server-v2' => 'GenuineIntel', + 'Cascadelake-Server-noTSX' => 'GenuineIntel', + 'Cascadelake-Server-v4' => 'GenuineIntel', + 'Cascadelake-Server-v5' => 'GenuineIntel', + 'Cooperlake' => 'GenuineIntel', + 'Cooperlake-v2' => 'GenuineIntel', + KnightsMill => 'GenuineIntel', + 'Icelake-Client' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 + 'Icelake-Client-noTSX' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 + 'Icelake-Server' => 'GenuineIntel', + 'Icelake-Server-noTSX' => 'GenuineIntel', + 'Icelake-Server-v3' => 'GenuineIntel', + 'Icelake-Server-v4' => 'GenuineIntel', + 'Icelake-Server-v5' => 'GenuineIntel', + 'Icelake-Server-v6' => 'GenuineIntel', + 'Icelake-Server-v7' => 'GenuineIntel', + 'SapphireRapids' => 'GenuineIntel', + 'SapphireRapids-v2' => 'GenuineIntel', + 'SapphireRapids-v3' => 'GenuineIntel', + 'SapphireRapids-v4' => 'GenuineIntel', + 'GraniteRapids' => 'GenuineIntel', + 'GraniteRapids-v2' => 'GenuineIntel', + 'GraniteRapids-v3' => 'GenuineIntel', + 'SierraForest' => 'GenuineIntel', + 'SierraForest-v2' => 'GenuineIntel', + 'SierraForest-v3' => 'GenuineIntel', + 'ClearwaterForest' => 'GenuineIntel', + + # AMD CPUs + athlon => 'AuthenticAMD', + phenom => 'AuthenticAMD', + Opteron_G1 => 'AuthenticAMD', + Opteron_G2 => 'AuthenticAMD', + Opteron_G3 => 'AuthenticAMD', + Opteron_G4 => 'AuthenticAMD', + Opteron_G5 => 'AuthenticAMD', + EPYC => 'AuthenticAMD', + 'EPYC-IBPB' => 'AuthenticAMD', + 'EPYC-v3' => 'AuthenticAMD', + 'EPYC-v4' => 'AuthenticAMD', + 'EPYC-v5' => 'AuthenticAMD', + 'EPYC-Rome' => 'AuthenticAMD', + 'EPYC-Rome-v2' => 'AuthenticAMD', + 'EPYC-Rome-v3' => 'AuthenticAMD', + 'EPYC-Rome-v4' => 'AuthenticAMD', + 'EPYC-Rome-v5' => 'AuthenticAMD', + 'EPYC-Milan' => 'AuthenticAMD', + 'EPYC-Milan-v2' => 'AuthenticAMD', + 'EPYC-Milan-v3' => 'AuthenticAMD', + 'EPYC-Genoa' => 'AuthenticAMD', + 'EPYC-Genoa-v2' => 'AuthenticAMD', + 'EPYC-Turin' => 'AuthenticAMD', + + # generic types, use vendor from host node + kvm32 => 'default', + kvm64 => 'default', + qemu32 => 'default', + qemu64 => 'default', + max => 'default', + }, + aarch64 => { + 'a64fx' => 'ARM', + 'cortex-a35' => 'ARM', + 'cortex-a53' => 'ARM', + 'cortex-a55' => 'ARM', + 'cortex-a57' => 'ARM', + 'cortex-a710' => 'ARM', + 'cortex-a72' => 'ARM', + 'cortex-a76' => 'ARM', + 'neoverse-n1' => 'ARM', + 'neoverse-n2' => 'ARM', + 'neoverse-v1' => 'ARM', + # 32 bit and deprecated models were not added + max => 'default', + }, + }; -my $all_cpu_models; -for my $arch (keys $cpu_models_by_arch->%*) { - for my $model (keys $cpu_models_by_arch->{$arch}->%*) { - $all_cpu_models->{$model} = $cpu_models_by_arch->{$arch}->{$model}; + my $host_arch = get_host_arch(); + # The host CPU model only exists if the arch matches + $cpu_models_by_arch->{$host_arch}->{host} = 'default'; + + for my $arch (keys $cpu_models_by_arch->%*) { + for my $model (keys $cpu_models_by_arch->{$arch}->%*) { + $all_cpu_models->{$model} = $cpu_models_by_arch->{$arch}->{$model}; + } } } +# returns the cpu models for the given architecture, or if $arch is not given, a +# map from available architectures to models +sub get_cpu_models_by_arch { + my ($arch) = @_; + initialize_cpu_models() if !defined($cpu_models_by_arch); + return $cpu_models_by_arch->{$arch} if defined($arch); + return $cpu_models_by_arch; +} + +# returns a map of all availble cpu models regardless of architecture +sub get_all_cpu_models { + initialize_cpu_models() if !defined($all_cpu_models); + return $all_cpu_models; +} + my $supported_cpu_flags_by_arch = { x86_64 => [ { @@ -325,7 +345,7 @@ my $cpu_fmt = { "CPU model and vendor to report to the guest. Must be a QEMU/KVM supported model." . " Only valid for custom CPU model definitions, default models will always report themselves to the guest OS.", type => 'string', - enum => [sort { lc("$a") cmp lc("$b") } keys $all_cpu_models->%*], + enum => [sort { lc("$a") cmp lc("$b") } keys get_all_cpu_models()->%*], default => 'kvm64', optional => 1, }, @@ -583,7 +603,7 @@ sub get_cpu_models { my ($include_custom, $arch) = @_; $arch = get_host_arch() if !defined($arch); - my $cpu_vendor_list = $cpu_models_by_arch->{$arch}; + my $cpu_vendor_list = get_cpu_models_by_arch($arch); my $models = []; @@ -614,7 +634,7 @@ sub get_cpu_models { for my $custom_model (keys %{ $conf->{ids} }) { my $reported_model = $conf->{ids}->{$custom_model}->{'reported-model'}; $reported_model //= $cpu_fmt->{'reported-model'}->{default}; - my $vendor = $all_cpu_models->{$reported_model}; + my $vendor = get_all_cpu_models()->{$reported_model}; push @$models, { name => "custom-$custom_model", @@ -870,7 +890,7 @@ sub get_cpu_options { } die "CPU model '$cputype' does not exist for configured vCPU architecture '$arch'\n" - if !defined($cpu_models_by_arch->{$arch}->{$cputype}); + if !defined(get_cpu_models_by_arch($arch)->{$cputype}); my $pve_flags = get_pve_cpu_flags($conf, $kvm, $cputype, $arch, $machine_version); @@ -910,7 +930,7 @@ sub get_cpu_options { if ($arch eq 'x86_64') { # $cputype is the "reported-model" for custom types, so we can just look up # the vendor in the default list - my $cpu_vendor = $cpu_models_by_arch->{$arch}->{$cputype} or die "internal error"; + my $cpu_vendor = get_cpu_models_by_arch($arch)->{$cputype} or die "internal error"; $pve_forced_flags->{'vendor'} = { value => $cpu_vendor } if $cpu_vendor ne 'default'; } diff --git a/src/test/run_config2command_tests.pl b/src/test/run_config2command_tests.pl index c20f2377..7ca2014e 100755 --- a/src/test/run_config2command_tests.pl +++ b/src/test/run_config2command_tests.pl @@ -235,6 +235,8 @@ sub parse_test($config_fn) { $testname = "'$testname' - $desc"; } $current_test->{testname} = $testname; + + PVE::QemuServer::CPUConfig::initialize_cpu_models(); } sub get_test_qemu_version { -- 2.47.3