public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
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	[thread overview]
Message-ID: <20260205141959.3615131-3-d.csapak@proxmox.com> (raw)
In-Reply-To: <20260205141959.3615131-1-d.csapak@proxmox.com>

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 <d.csapak@proxmox.com>
---
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





  parent reply	other threads:[~2026-02-05 14:19 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-05 14:17 [PATCH qemu-server v3 0/3] improve multiarch build support Dominik Csapak
2026-02-05 14:17 ` [PATCH qemu-server v3 1/3] tests: improve multiarch build support by introducing local get_host_arch helper Dominik Csapak
2026-02-05 14:17 ` Dominik Csapak [this message]
2026-02-05 14:17 ` [PATCH qemu-server v3 3/3] tests: cfg2cmd: add some architecture tests Dominik Csapak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260205141959.3615131-3-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal