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 0D2091FF138 for ; Wed, 04 Feb 2026 16:46:28 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0015A18CDD; Wed, 4 Feb 2026 16:46:58 +0100 (CET) Message-ID: <88e10fbe-3231-40da-8ea2-d95fc1576715@proxmox.com> Date: Wed, 4 Feb 2026 16:46:52 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Beta Subject: Re: [PATCH qemu-server v2 1/2] tests: improve multiarch build support To: Dominik Csapak , pve-devel@lists.proxmox.com References: <20260204100425.1303295-1-d.csapak@proxmox.com> Content-Language: en-US From: Thomas Lamprecht In-Reply-To: <20260204100425.1303295-1-d.csapak@proxmox.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1770219936783 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.022 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: DC7S3FMRT7A5JOSI5IADDPFTRUG7SKG2 X-Message-ID-Hash: DC7S3FMRT7A5JOSI5IADDPFTRUG7SKG2 X-MailFrom: t.lamprecht@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: Am 04.02.26 um 11:04 schrieb Dominik Csapak: > instead of simply saving 'host_arch' in the global package namespace, > use the PVE::Tools::get_host_arch helper, which caches the result > anyway. > > For easier testing: > * introduce our own helper for getting the host arch, which uses > the PVE::Tools one. So we only have to mock the Tools one to get > correct behavior in the tests. Use this everywhere here where we need > it. > * move the cpu_models_by_arch initialization into a sub that can be > called by the tests to re-initialize. > > Signed-off-by: Dominik Csapak > --- > changes from v1: > * add helpers to be more easily used and mocked by the tests instead > of modifying the module level variable > > src/PVE/QemuServer.pm | 5 +- > src/PVE/QemuServer/CPUConfig.pm | 258 ++++++++++++++------------- > src/PVE/QemuServer/Helpers.pm | 8 +- > src/test/run_config2command_tests.pl | 8 +- > 4 files changed, 146 insertions(+), 133 deletions(-) > > diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm > index 5d2dbe03..8bf23945 100644 > --- a/src/PVE/QemuServer.pm > +++ b/src/PVE/QemuServer.pm > @@ -46,8 +46,7 @@ use PVE::SafeSyslog; > use PVE::Storage; > use PVE::SysFSTools; > use PVE::Systemd; > -use PVE::Tools > - qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE); > +use PVE::Tools qw(run_command file_read_firstline file_get_contents dir_glob_foreach $IPV6RE); > > use PVE::QMPClient; > use PVE::QemuConfig; > @@ -58,7 +57,7 @@ use PVE::QemuServer::Blockdev; > use PVE::QemuServer::BlockJob; > use PVE::QemuServer::Cfg2Cmd; > use PVE::QemuServer::Helpers > - qw(config_aware_timeout get_iscsi_initiator_name min_version kvm_user_version windows_version); > + qw(config_aware_timeout get_iscsi_initiator_name get_host_arch min_version kvm_user_version windows_version); > use PVE::QemuServer::Cloudinit; > use PVE::QemuServer::CGroup; > use PVE::QemuServer::CPUConfig qw( > diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm > index 32ec4954..7d5559b0 100644 > --- a/src/PVE/QemuServer/CPUConfig.pm > +++ b/src/PVE/QemuServer/CPUConfig.pm > @@ -11,7 +11,7 @@ use PVE::ProcFSTools; > use PVE::RESTEnvironment qw(log_warn); > use PVE::Tools qw(run_command); > > -use PVE::QemuServer::Helpers qw(min_version); > +use PVE::QemuServer::Helpers qw(min_version get_host_arch); > > use base qw(PVE::SectionConfig Exporter); > > @@ -25,8 +25,6 @@ our @EXPORT_OK = qw( > get_cvm_type > ); > > -my $host_arch = PVE::Tools::get_host_arch(); > - > my $arch_desc = { > description => "Virtual processor architecture. Defaults to the host architecture.", > type => 'string', > @@ -100,130 +98,138 @@ 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 > +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}; > + } > } > } > > +initialize_cpu_models(); this now still always does this on module load, would be nicer to actually only pay for that if needed by adding getter methods for each variable, like sub get_all_cpu_models { initialize_cpu_models() if !defined($all_cpu_models); return $all_cpu_models; } Same with a get_cpu_models_by_arch getter. And I'd split this and the host_arch change into separate patches, they are rather unrelated to each other.