Skip to content

Commit 200ad5e

Browse files
committed
Add cpu policy helper and test
Add a CPU policy tooling to be able to check for certain CPU feature. The test_cpu_policy also logs hosts CPU policies for debugging purposes. Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
1 parent b2b7612 commit 200ad5e

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

jobs.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,12 @@ class JobData(TypedDict):
469469
"--vm[]": "multi/limits",
470470
},
471471
"paths": ["tests/limits"],
472+
},
473+
"cpu-policy": {
474+
"description": "Tests displaying CPU policies",
475+
"nb_pools": 1,
476+
"params": {},
477+
"paths": ["tests/misc/test_cpu_policy.py"]
472478
}
473479
}
474480

lib/cpu_policy.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from lib.host import Host
2+
3+
NO_SUBLEAF = 0xffffffff
4+
5+
class CpuPolicy:
6+
"""A specific CPU policy (PV, HVM, ...)"""
7+
# (leaf, subleaf) -> (eax, ebx, ecx, edx)
8+
cpuid: dict[(int, int), (int, int, int, int)]
9+
# msr -> val
10+
msr: dict[int, int]
11+
12+
def __init__(self, cpuid: dict[(int, int), int], msr: dict[int, int]):
13+
self.cpuid = cpuid
14+
self.msr = msr
15+
16+
class HostCpuPolicy:
17+
"""All CPU policies of a host (CPUID, specific MSRs)"""
18+
policies: dict[str, CpuPolicy]
19+
20+
def __init__(self, host: Host):
21+
self.policies = dict()
22+
text = host.ssh("xen-cpuid --policy")
23+
current_policy: CpuPolicy = None
24+
mode = None # None | "cpuid" | "msr"
25+
26+
lines = text.splitlines()
27+
28+
for line in lines:
29+
line = line.rstrip()
30+
31+
# ---- Policy header ----
32+
if "policy:" in line:
33+
# Example: "Raw policy: 32 leaves, 2 MSRs"
34+
name, rest = line.split("policy:", 1)
35+
name = name.strip()
36+
37+
self.policies[name] = CpuPolicy(dict(), dict())
38+
current_policy = self.policies[name]
39+
mode = None
40+
continue
41+
42+
if current_policy is None:
43+
continue
44+
45+
# ---- Section switches ----
46+
if line.strip() == "CPUID:":
47+
mode = "cpuid"
48+
continue
49+
50+
if line.strip() == "MSRs:":
51+
mode = "msr"
52+
continue
53+
54+
# Skip table headers
55+
if "leaf" in line or "index" in line or not line.strip():
56+
continue
57+
58+
# ---- CPUID parsing ----
59+
if mode == "cpuid":
60+
# Example:
61+
# 00000004:00000003 -> 1c03c163:02c0003f:00001fff:00000006
62+
left, right = line.split("->")
63+
leaf_hex, subleaf_hex = left.strip().split(":")
64+
eax, ebx, ecx, edx = right.strip().split(":")
65+
66+
key = (int(leaf_hex, 16), int(subleaf_hex, 16))
67+
current_policy.cpuid[key] = (
68+
int(eax, 16),
69+
int(ebx, 16),
70+
int(ecx, 16),
71+
int(edx, 16)
72+
)
73+
continue
74+
75+
# ---- MSR parsing ----
76+
if mode == "msr":
77+
# Example:
78+
# 0000010a -> 400000000c000000
79+
idx_hex, val_hex = line.split("->")
80+
idx = int(idx_hex.strip(), 16)
81+
val = int(val_hex.strip(), 16)
82+
current_policy.msr[idx] = val
83+
continue

tests/misc/test_cpu_policy.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
import logging
4+
5+
from lib.cpu_policy import NO_SUBLEAF, HostCpuPolicy
6+
7+
class TestCpuPolicy:
8+
def test_cpu_policy(self, host):
9+
cpu_policy = HostCpuPolicy(host)
10+
11+
for name, policy in cpu_policy.policies.items():
12+
for ((leaf, subleaf), (eax, ebx, ecx, edx)) in policy.cpuid.items():
13+
logging.info(f"CPUID[{name}]: {leaf:08x}:{subleaf:08x} -> {eax:08x}:{ebx:08x}:{ecx:08x}:{edx:08x}")
14+
15+
for (msr, val) in policy.msr.items():
16+
logging.info(f"MSR [{name}]: {msr:08x} -> {val:08x}")

0 commit comments

Comments
 (0)