[libvirt] [PATCH 10/14] cputest: Add "diff" command to cpu-cpuid.py

Pavel Hrdina phrdina at redhat.com
Mon Mar 27 14:10:27 UTC 2017


On Fri, Mar 17, 2017 at 05:36:48PM +0100, Jiri Denemark wrote:
> 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 at redhat.com>
> ---
>  tests/cputestdata/cpu-cpuid.py | 89 +++++++++++++++++++++++++++++++++++++++++-
>  tests/cputestdata/cpu-parse.sh |  1 +
>  2 files changed, 89 insertions(+), 1 deletion(-)
> 
> diff --git a/tests/cputestdata/cpu-cpuid.py b/tests/cputestdata/cpu-cpuid.py
> index f4cf6d440..4b9b04ace 100755
> --- a/tests/cputestdata/cpu-cpuid.py
> +++ b/tests/cputestdata/cpu-cpuid.py
> @@ -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,50 @@ 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"]:

I would probably use a new variable to store the converted data, just in
case that we don't mess up the original data.  Currently it works but it
could bite us in the future and it would be hard to debug.

> +        leaf["in_eax"] = int(leaf["@eax_in"], 0)
> +        leaf["in_ecx"] = int(leaf["@ecx_in"], 0)
> +        for reg in ["eax", "ebx", "ecx", "edx"]:
> +            leaf[reg] = int(leaf["@" + reg], 0)
> +
> +        cpuidAdd(cpuid, leaf)
> +
> +    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' "
> +                line += "eax='0x%08x' ebx='0x%08x' "
> +                line += "ecx='0x%08x' edx='0x%08x'/>\n"

It is possible to split the long string into multiple lines like this:

line = ("string 1"
        "string 2")

> +                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 +316,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 +348,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)
> diff --git a/tests/cputestdata/cpu-parse.sh b/tests/cputestdata/cpu-parse.sh
> index d823c399b..cd1ab024b 100755
> --- a/tests/cputestdata/cpu-parse.sh
> +++ b/tests/cputestdata/cpu-parse.sh
> @@ -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
> -- 
> 2.12.0
> 
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20170327/6d9ac33e/attachment-0001.sig>


More information about the libvir-list mailing list