99from packaging import version
1010
1111import framework .utils_cpuid as utils
12+ from framework .artifacts import GUEST_KERNEL_DEFAULT , pin_guest_kernel
1213from framework .properties import global_props
1314from framework .utils import get_kernel_version
1415
@@ -35,7 +36,7 @@ def _check_cpu_topology(
3536 expected_lscpu_output = {
3637 "CPU(s)" : str (expected_cpu_count ),
3738 "On-line CPU(s) list" : expected_cpus_list ,
38- "Thread(s) per core" : "1" ,
39+ "Thread(s) per core" : str ( expected_threads_per_core ) ,
3940 "Core(s) per cluster" : str (
4041 int (expected_cpu_count / expected_threads_per_core )
4142 ),
@@ -59,14 +60,16 @@ def _check_cpu_topology(
5960 "depth 7" : f"{ expected_cpu_count } PU (type #3)" ,
6061 }
6162 else :
63+ threads_per_core = expected_threads_per_core
64+ cores = int (expected_cpu_count / threads_per_core )
6265 expected_hwloc_output = {
6366 "depth 0" : "1 Machine (type #0)" ,
6467 "depth 1" : "1 Package (type #1)" ,
6568 "depth 2" : "1 L3Cache (type #6)" ,
66- "depth 3" : f"{ expected_cpu_count } L2Cache (type #5)" ,
67- "depth 4" : f"{ expected_cpu_count } L1dCache (type #4)" ,
68- "depth 5" : f"{ expected_cpu_count } L1iCache (type #9)" ,
69- "depth 6" : f"{ expected_cpu_count } Core (type #2)" ,
69+ "depth 3" : f"{ cores if threads_per_core > 1 else expected_cpu_count } L2Cache (type #5)" ,
70+ "depth 4" : f"{ cores if threads_per_core > 1 else expected_cpu_count } L1dCache (type #4)" ,
71+ "depth 5" : f"{ cores if threads_per_core > 1 else expected_cpu_count } L1iCache (type #9)" ,
72+ "depth 6" : f"{ cores } Core (type #2)" ,
7073 "depth 7" : f"{ expected_cpu_count } PU (type #3)" ,
7174 }
7275
@@ -192,15 +195,43 @@ def _check_cache_topology_arm(test_microvm, no_cpus, kernel_version_tpl):
192195 assert guest_slice == host_slice
193196
194197
198+ @pin_guest_kernel (GUEST_KERNEL_DEFAULT )
199+ @pytest .mark .parametrize ("num_vcpus" , [2 , 4 ])
200+ def test_aarch64_smt_threads_per_core (uvm , num_vcpus ):
201+ """
202+ Check the guest-visible SMT topology without asserting cache hierarchy details.
203+ """
204+ if PLATFORM != "aarch64" :
205+ pytest .skip ("This test verifies aarch64 SMT topology." )
206+
207+ vm = uvm
208+ vm .spawn ()
209+ vm .basic_config (vcpu_count = num_vcpus , smt = True )
210+ vm .add_net_iface ()
211+ vm .start ()
212+
213+ utils .check_guest_cpuid_output (
214+ vm ,
215+ "lscpu" ,
216+ None ,
217+ ":" ,
218+ {
219+ "CPU(s)" : str (num_vcpus ),
220+ "On-line CPU(s) list" : "0,1" if num_vcpus == 2 else "0-3" ,
221+ "Thread(s) per core" : "2" ,
222+ "Core(s) per cluster" : str (num_vcpus // 2 ),
223+ "Cluster(s)" : "1" ,
224+ "NUMA node(s)" : "1" ,
225+ },
226+ )
227+
228+
195229@pytest .mark .parametrize ("num_vcpus" , [1 , 2 , 16 ])
196230@pytest .mark .parametrize ("htt" , [True , False ], ids = ["HTT_ON" , "HTT_OFF" ])
197231def test_cpu_topology (uvm , num_vcpus , htt ):
198232 """
199233 Check the CPU topology for a microvm with the specified config.
200234 """
201- if htt and PLATFORM == "aarch64" :
202- pytest .skip ("SMT is configurable only on x86." )
203-
204235 # TODO:Remove (or adapt) this once we unify the way we expose the CPU cache hierarchy on
205236 # Aarch64 systems.
206237 if version .parse (get_kernel_version ()) >= version .parse ("6.14" ):
@@ -232,8 +263,6 @@ def test_cache_topology(uvm, num_vcpus, htt):
232263 """
233264 Check the cache topology for a microvm with the specified config.
234265 """
235- if htt and PLATFORM == "aarch64" :
236- pytest .skip ("SMT is configurable only on x86." )
237266 vm = uvm
238267 vm .spawn ()
239268 vm .basic_config (vcpu_count = num_vcpus , smt = htt )
0 commit comments