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
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
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
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 :|
© 2016 - 2026 Red Hat, Inc.