]> xenbits.xensource.com Git - libvirt.git/commitdiff
cputest: Add "diff" command to cpu-cpuid.py
authorJiri Denemark <jdenemar@redhat.com>
Thu, 16 Mar 2017 11:25:30 +0000 (12:25 +0100)
committerJiri Denemark <jdenemar@redhat.com>
Mon, 27 Mar 2017 14:29:27 +0000 (16:29 +0200)
The new command can be used to generate test data for virCPUUpdateLive.

When "cpu-cpuid.py diff x86-cpuid-Something.json" is run, it reads raw
CPUID data stored in x86-cpuid-Something.xml and CPUID data from QEMU
stored in x86-cpuid-Something.json to produce two more CPUID files:
x86-cpuid-Something-enabled.xml and x86-cpuid-Something-disabled.xml.

- x86-cpuid-Something-enabled.xml will contain CPUID bits present in
    x86-cpuid-Something.json (i.e., enabled by QEMU for the "host" CPU)

- x86-cpuid-Something-disabled.xml will contain all CPUID bits from
    x86-cpuid-Something.xml which are not present in
    x86-cpuid-Something.json (i.e., CPUID bits which the host CPU
    supports, but QEMU does not enable them for the "host" CPU)

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
tests/cputestdata/cpu-cpuid.py
tests/cputestdata/cpu-parse.sh

index f4cf6d4408654976e1350d38cf52a74cad715b86..00d86eb258857a210878be3b94eeb671880a7598 100755 (executable)
@@ -2,6 +2,7 @@
 
 import sys
 import json
+import xmltodict
 
 # This is a list of x86 CPU features as of QEMU 2.8.50 and it won't need any
 # updates since in the future because query-cpu-model-expansion will be used
@@ -171,6 +172,16 @@ cpuidMap = [
 ]
 
 
+def reverseCpuidMap():
+    features = {}
+
+    for feature in cpuidMap:
+        for name in feature["names"]:
+            features[name] = feature
+
+    return features
+
+
 def cpuidIsSet(cpuid, feature):
     in_eax = feature["in_eax"]
     in_ecx = feature["in_ecx"]
@@ -201,6 +212,12 @@ def cpuidLeaf(cpuid, in_eax, in_ecx):
     return leaf
 
 
+def cpuidAdd(cpuid, feature):
+    leaf = cpuidLeaf(cpuid, feature["in_eax"], feature["in_ecx"])
+    for reg in ["eax", "ebx", "ecx", "edx"]:
+        leaf[reg] |= feature[reg]
+
+
 def parseFeatureWords(path):
     features = None
 
@@ -240,6 +257,51 @@ def parseFeatureWords(path):
     return props, cpuid
 
 
+def parseQemu(path, features):
+    cpuid = {}
+    with open(path, "r") as f:
+        data = json.load(f)
+
+    for (prop, val) in data["return"]["model"]["props"].iteritems():
+        if val and prop in features:
+            cpuidAdd(cpuid, features[prop])
+
+    return cpuid
+
+
+def parseCpuid(path):
+    cpuid = {}
+    with open(path, "r") as f:
+        data = xmltodict.parse(f)
+
+    for leaf in data["cpudata"]["cpuid"]:
+        feature = {}
+        feature["in_eax"] = int(leaf["@eax_in"], 0)
+        feature["in_ecx"] = int(leaf["@ecx_in"], 0)
+        for reg in ["eax", "ebx", "ecx", "edx"]:
+            feature[reg] = int(leaf["@" + reg], 0)
+
+        cpuidAdd(cpuid, feature)
+
+    return cpuid
+
+
+def formatCpuid(cpuid, path, comment):
+    with open(path, "w") as f:
+        f.write("<!-- " + comment + " -->\n")
+        f.write("<cpudata arch='x86'>\n")
+        for in_eax in sorted(cpuid.keys()):
+            for in_ecx in sorted(cpuid[in_eax].keys()):
+                leaf = cpuid[in_eax][in_ecx]
+                line = ("  <cpuid eax_in='0x%08x' ecx_in='0x%02x' "
+                        "eax='0x%08x' ebx='0x%08x' "
+                        "ecx='0x%08x' edx='0x%08x'/>\n")
+                f.write(line %(
+                        in_eax, in_ecx,
+                        leaf["eax"], leaf["ebx"], leaf["ecx"], leaf["edx"]))
+        f.write("</cpudata>\n")
+
+
 def convert(path):
     props, cpuid = parseFeatureWords(path)
 
@@ -255,8 +317,30 @@ def convert(path):
         f.write("\n")
 
 
+def diff(features, path):
+    base = path.replace(".json", "")
+    jsonFile = path
+    cpuidFile = base + ".xml"
+    enabledFile = base + "-enabled.xml"
+    disabledFile = base + "-disabled.xml"
+
+    cpuid = parseCpuid(cpuidFile)
+    qemu = parseQemu(jsonFile, features)
+
+    enabled = {}
+    disabled = {}
+    for feature in cpuidMap:
+        if cpuidIsSet(qemu, feature):
+            cpuidAdd(enabled, feature)
+        elif cpuidIsSet(cpuid, feature):
+            cpuidAdd(disabled, feature)
+
+    formatCpuid(enabled, enabledFile, "Features enabled by QEMU")
+    formatCpuid(disabled, disabledFile, "Features disabled by QEMU")
+
+
 if len(sys.argv) < 3:
-    print "Usage: %s convert json_file..." % sys.argv[0]
+    print "Usage: %s convert|diff json_file..." % sys.argv[0]
     sys.exit(1)
 
 action = sys.argv[1]
@@ -265,6 +349,10 @@ args = sys.argv[2:]
 if action == "convert":
     for path in args:
         convert(path)
+elif action == "diff":
+    features = reverseCpuidMap()
+    for path in args:
+        diff(features, path)
 else:
     print "Unknown action: " + action
     sys.exit(1)
index d823c399b0f76b5218632fc3d529123d10861946..cd1ab024b33cf61ac249b84b3ccf7e71e79d57c3 100755 (executable)
@@ -55,6 +55,7 @@ if [[ -s $fname.json ]]; then
     if ! grep -q model-expansion $fname.json; then
         $(dirname $0)/cpu-cpuid.py convert $fname.json
     fi
+    $(dirname $0)/cpu-cpuid.py diff $fname.json
 else
     rm $fname.json
 fi