[PATCH v3 3/4] scripts: helper to generate x86_64 CPU ABI compat info

Daniel P. Berrangé posted 4 patches 4 years, 8 months ago
[PATCH v3 3/4] scripts: helper to generate x86_64 CPU ABI compat info
Posted by Daniel P. Berrangé 4 years, 8 months ago
This script is what is used to generate the docs data table in:

  docs/system/cpu-models-x86-abi.csv

It can be useful to run if adding new CPU models / versions and
the csv needs updating.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 scripts/cpu-x86-uarch-abi.py | 194 +++++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)
 create mode 100644 scripts/cpu-x86-uarch-abi.py

diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py
new file mode 100644
index 0000000000..08acc52a81
--- /dev/null
+++ b/scripts/cpu-x86-uarch-abi.py
@@ -0,0 +1,194 @@
+#!/usr/bin/python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# A script to generate a CSV file showing the x86_64 ABI
+# compatibility levels for each CPU model.
+#
+
+from qemu import qmp
+import sys
+
+if len(sys.argv) != 1:
+    print("syntax: %s QMP-SOCK\n\n" % __file__ +
+          "Where QMP-SOCK points to a QEMU process such as\n\n" +
+          " # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " +
+          "-display none -accel kvm", file=sys.stderr)
+    sys.exit(1)
+
+# Mandatory CPUID features for each microarch ABI level
+levels = [
+    [ # x86-64 baseline
+        "cmov",
+        "cx8",
+        "fpu",
+        "fxsr",
+        "mmx",
+        "syscall",
+        "sse",
+        "sse2",
+    ],
+    [ # x86-64-v2
+        "cx16",
+        "lahf-lm",
+        "popcnt",
+        "pni",
+        "sse4.1",
+        "sse4.2",
+        "ssse3",
+    ],
+    [ # x86-64-v3
+        "avx",
+        "avx2",
+        "bmi1",
+        "bmi2",
+        "f16c",
+        "fma",
+        "abm",
+        "movbe",
+    ],
+    [ # x86-64-v4
+        "avx512f",
+        "avx512bw",
+        "avx512cd",
+        "avx512dq",
+        "avx512vl",
+    ],
+]
+
+# Assumes externally launched process such as
+#
+#   qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
+#
+# Note different results will be obtained with TCG, as
+# TCG masks out certain features otherwise present in
+# the CPU model definitions, as does KVM.
+
+
+sock = sys.argv[1]
+cmd = sys.argv[2]
+shell = qmp.QEMUMonitorProtocol(sock)
+shell.connect()
+
+models = shell.cmd("query-cpu-definitions")
+
+# These QMP props don't correspond to CPUID fatures
+# so ignore them
+skip = [
+    "family",
+    "min-level",
+    "min-xlevel",
+    "vendor",
+    "model",
+    "model-id",
+    "stepping",
+]
+
+names = []
+
+for model in models["return"]:
+    if "alias-of" in model:
+        continue
+    names.append(model["name"])
+
+models = {}
+
+for name in sorted(names):
+    cpu = shell.cmd("query-cpu-model-expansion",
+                     { "type": "static",
+                       "model": { "name": name }})
+
+    got = {}
+    for (feature, present) in cpu["return"]["model"]["props"].items():
+        if present and feature not in skip:
+            got[feature] = True
+
+    if name in ["host", "max", "base"]:
+        continue
+
+    models[name] = {
+        # Dict of all present features in this CPU model
+        "features": got,
+
+        # Whether each x86-64 ABI level is satisfied
+        "levels": [False, False, False, False],
+
+        # Number of extra CPUID features compared to the x86-64 ABI level
+        "distance":[-1, -1, -1, -1],
+
+        # CPUID features present in model, but not in ABI level
+        "delta":[[], [], [], []],
+
+        # CPUID features in ABI level but not present in model
+        "missing": [[], [], [], []],
+    }
+
+
+# Calculate whether the CPU models satisfy each ABI level
+for name in models.keys():
+    for level in range(len(levels)):
+        got = set(models[name]["features"])
+        want = set(levels[level])
+        missing = want - got
+        match = True
+        if len(missing) > 0:
+            match = False
+        models[name]["levels"][level] = match
+        models[name]["missing"][level] = missing
+
+# Cache list of CPU models satisfying each ABI level
+abi_models = [
+    [],
+    [],
+    [],
+    [],
+]
+
+for name in models.keys():
+    for level in range(len(levels)):
+        if models[name]["levels"][level]:
+            abi_models[level].append(name)
+
+
+for level in range(len(abi_models)):
+    # Find the union of features in all CPU models satisfying this ABI
+    allfeatures = {}
+    for name in abi_models[level]:
+        for feat in models[name]["features"]:
+            allfeatures[feat] = True
+
+    # Find the intersection of features in all CPU models satisfying this ABI
+    commonfeatures = []
+    for feat in allfeatures:
+        present = True
+        for name in models.keys():
+            if not models[name]["levels"][level]:
+                continue
+            if feat not in models[name]["features"]:
+                present = False
+        if present:
+            commonfeatures.append(feat)
+
+    # Determine how many extra features are present compared to the lowest
+    # common denominator
+    for name in models.keys():
+        if not models[name]["levels"][level]:
+            continue
+
+        delta = set(models[name]["features"].keys()) - set(commonfeatures)
+        models[name]["distance"][level] = len(delta)
+        models[name]["delta"][level] = delta
+
+def print_uarch_abi_csv():
+    print("# Automatically generated from '%s'" % __file__)
+    print("Model,baseline,v2,v3,v4")
+    for name in models.keys():
+        print(name, end="")
+        for level in range(len(levels)):
+            if models[name]["levels"][level]:
+                print(",✅", end="")
+            else:
+                print(",", end="")
+        print()
+
+print_uarch_abi_csv()
-- 
2.31.1


Re: [PATCH v3 3/4] scripts: helper to generate x86_64 CPU ABI compat info
Posted by Eduardo Habkost 4 years, 8 months ago
On Mon, Jun 07, 2021 at 02:58:42PM +0100, Daniel P. Berrangé wrote:
[...]
> +# Assumes externally launched process such as
> +#
> +#   qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
> +#
> +# Note different results will be obtained with TCG, as
> +# TCG masks out certain features otherwise present in
> +# the CPU model definitions, as does KVM.
> +
> +
> +sock = sys.argv[1]
> +cmd = sys.argv[2]
> +shell = qmp.QEMUMonitorProtocol(sock)
> +shell.connect()
> +
> +models = shell.cmd("query-cpu-definitions")

I would make the script launch QEMU itself, using the QEMUMachine
class.

But life is too short for polishing a quick utility script, so:

Acked-by: Eduardo Habkost <ehabkost@redhat.com>

I plan to queue this once I review the rest of the series.

-- 
Eduardo


Re: [PATCH v3 3/4] scripts: helper to generate x86_64 CPU ABI compat info
Posted by Eduardo Habkost 4 years, 8 months ago
On Mon, Jun 07, 2021 at 02:11:44PM -0300, Eduardo Habkost wrote:
> On Mon, Jun 07, 2021 at 02:58:42PM +0100, Daniel P. Berrangé wrote:
> [...]
> > +# Assumes externally launched process such as
> > +#
> > +#   qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
> > +#
> > +# Note different results will be obtained with TCG, as
> > +# TCG masks out certain features otherwise present in
> > +# the CPU model definitions, as does KVM.
> > +
> > +
> > +sock = sys.argv[1]
> > +cmd = sys.argv[2]
> > +shell = qmp.QEMUMonitorProtocol(sock)
> > +shell.connect()
> > +
> > +models = shell.cmd("query-cpu-definitions")
> 
> I would make the script launch QEMU itself, using the QEMUMachine
> class.
> 
> But life is too short for polishing a quick utility script, so:
> 
> Acked-by: Eduardo Habkost <ehabkost@redhat.com>
> 
> I plan to queue this once I review the rest of the series.

I'm queueing patch 1/4 and this one.

I'm not sure about the lowest common denominator approach for
generating the CPU models in patch 2/4, but I need to read your
the cover letter more carefully, to be able to comment.

-- 
Eduardo


Re: [PATCH v3 3/4] scripts: helper to generate x86_64 CPU ABI compat info
Posted by Daniel P. Berrangé 4 years, 8 months ago
On Mon, Jun 07, 2021 at 02:58:42PM +0100, Daniel P. Berrangé wrote:
> This script is what is used to generate the docs data table in:
> 
>   docs/system/cpu-models-x86-abi.csv
> 
> It can be useful to run if adding new CPU models / versions and
> the csv needs updating.
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
>  scripts/cpu-x86-uarch-abi.py | 194 +++++++++++++++++++++++++++++++++++
>  1 file changed, 194 insertions(+)
>  create mode 100644 scripts/cpu-x86-uarch-abi.py

Sorry I messed up just before sending this when I deleted some
code and incorrectly fixed up argv handling. Since you mentioned
you've queued it, it needs two changes

> 
> diff --git a/scripts/cpu-x86-uarch-abi.py b/scripts/cpu-x86-uarch-abi.py
> new file mode 100644
> index 0000000000..08acc52a81
> --- /dev/null
> +++ b/scripts/cpu-x86-uarch-abi.py
> @@ -0,0 +1,194 @@
> +#!/usr/bin/python3
> +#
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# A script to generate a CSV file showing the x86_64 ABI
> +# compatibility levels for each CPU model.
> +#
> +
> +from qemu import qmp
> +import sys
> +
> +if len(sys.argv) != 1:

s/1/2/

> +    print("syntax: %s QMP-SOCK\n\n" % __file__ +
> +          "Where QMP-SOCK points to a QEMU process such as\n\n" +
> +          " # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " +
> +          "-display none -accel kvm", file=sys.stderr)
> +    sys.exit(1)
> +
> +# Mandatory CPUID features for each microarch ABI level
> +levels = [
> +    [ # x86-64 baseline
> +        "cmov",
> +        "cx8",
> +        "fpu",
> +        "fxsr",
> +        "mmx",
> +        "syscall",
> +        "sse",
> +        "sse2",
> +    ],
> +    [ # x86-64-v2
> +        "cx16",
> +        "lahf-lm",
> +        "popcnt",
> +        "pni",
> +        "sse4.1",
> +        "sse4.2",
> +        "ssse3",
> +    ],
> +    [ # x86-64-v3
> +        "avx",
> +        "avx2",
> +        "bmi1",
> +        "bmi2",
> +        "f16c",
> +        "fma",
> +        "abm",
> +        "movbe",
> +    ],
> +    [ # x86-64-v4
> +        "avx512f",
> +        "avx512bw",
> +        "avx512cd",
> +        "avx512dq",
> +        "avx512vl",
> +    ],
> +]
> +
> +# Assumes externally launched process such as
> +#
> +#   qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
> +#
> +# Note different results will be obtained with TCG, as
> +# TCG masks out certain features otherwise present in
> +# the CPU model definitions, as does KVM.
> +
> +
> +sock = sys.argv[1]
> +cmd = sys.argv[2]

Delete this line since sys.argv[2] is not required

> +shell = qmp.QEMUMonitorProtocol(sock)
> +shell.connect()
> +
> +models = shell.cmd("query-cpu-definitions")


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|