]> git.proxmox.com Git - mirror_qemu.git/blame - scripts/cpu-x86-uarch-abi.py
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
[mirror_qemu.git] / scripts / cpu-x86-uarch-abi.py
CommitLineData
4e2f5f3a
DB
1#!/usr/bin/python3
2#
3# SPDX-License-Identifier: GPL-2.0-or-later
4#
5# A script to generate a CSV file showing the x86_64 ABI
6# compatibility levels for each CPU model.
7#
8
9from qemu import qmp
10import sys
11
12if len(sys.argv) != 1:
13 print("syntax: %s QMP-SOCK\n\n" % __file__ +
14 "Where QMP-SOCK points to a QEMU process such as\n\n" +
15 " # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " +
16 "-display none -accel kvm", file=sys.stderr)
17 sys.exit(1)
18
19# Mandatory CPUID features for each microarch ABI level
20levels = [
21 [ # x86-64 baseline
22 "cmov",
23 "cx8",
24 "fpu",
25 "fxsr",
26 "mmx",
27 "syscall",
28 "sse",
29 "sse2",
30 ],
31 [ # x86-64-v2
32 "cx16",
33 "lahf-lm",
34 "popcnt",
35 "pni",
36 "sse4.1",
37 "sse4.2",
38 "ssse3",
39 ],
40 [ # x86-64-v3
41 "avx",
42 "avx2",
43 "bmi1",
44 "bmi2",
45 "f16c",
46 "fma",
47 "abm",
48 "movbe",
49 ],
50 [ # x86-64-v4
51 "avx512f",
52 "avx512bw",
53 "avx512cd",
54 "avx512dq",
55 "avx512vl",
56 ],
57]
58
59# Assumes externally launched process such as
60#
61# qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait -display none -accel kvm
62#
63# Note different results will be obtained with TCG, as
64# TCG masks out certain features otherwise present in
65# the CPU model definitions, as does KVM.
66
67
68sock = sys.argv[1]
69cmd = sys.argv[2]
70shell = qmp.QEMUMonitorProtocol(sock)
71shell.connect()
72
73models = shell.cmd("query-cpu-definitions")
74
75# These QMP props don't correspond to CPUID fatures
76# so ignore them
77skip = [
78 "family",
79 "min-level",
80 "min-xlevel",
81 "vendor",
82 "model",
83 "model-id",
84 "stepping",
85]
86
87names = []
88
89for model in models["return"]:
90 if "alias-of" in model:
91 continue
92 names.append(model["name"])
93
94models = {}
95
96for name in sorted(names):
97 cpu = shell.cmd("query-cpu-model-expansion",
98 { "type": "static",
99 "model": { "name": name }})
100
101 got = {}
102 for (feature, present) in cpu["return"]["model"]["props"].items():
103 if present and feature not in skip:
104 got[feature] = True
105
106 if name in ["host", "max", "base"]:
107 continue
108
109 models[name] = {
110 # Dict of all present features in this CPU model
111 "features": got,
112
113 # Whether each x86-64 ABI level is satisfied
114 "levels": [False, False, False, False],
115
116 # Number of extra CPUID features compared to the x86-64 ABI level
117 "distance":[-1, -1, -1, -1],
118
119 # CPUID features present in model, but not in ABI level
120 "delta":[[], [], [], []],
121
122 # CPUID features in ABI level but not present in model
123 "missing": [[], [], [], []],
124 }
125
126
127# Calculate whether the CPU models satisfy each ABI level
128for name in models.keys():
129 for level in range(len(levels)):
130 got = set(models[name]["features"])
131 want = set(levels[level])
132 missing = want - got
133 match = True
134 if len(missing) > 0:
135 match = False
136 models[name]["levels"][level] = match
137 models[name]["missing"][level] = missing
138
139# Cache list of CPU models satisfying each ABI level
140abi_models = [
141 [],
142 [],
143 [],
144 [],
145]
146
147for name in models.keys():
148 for level in range(len(levels)):
149 if models[name]["levels"][level]:
150 abi_models[level].append(name)
151
152
153for level in range(len(abi_models)):
154 # Find the union of features in all CPU models satisfying this ABI
155 allfeatures = {}
156 for name in abi_models[level]:
157 for feat in models[name]["features"]:
158 allfeatures[feat] = True
159
160 # Find the intersection of features in all CPU models satisfying this ABI
161 commonfeatures = []
162 for feat in allfeatures:
163 present = True
164 for name in models.keys():
165 if not models[name]["levels"][level]:
166 continue
167 if feat not in models[name]["features"]:
168 present = False
169 if present:
170 commonfeatures.append(feat)
171
172 # Determine how many extra features are present compared to the lowest
173 # common denominator
174 for name in models.keys():
175 if not models[name]["levels"][level]:
176 continue
177
178 delta = set(models[name]["features"].keys()) - set(commonfeatures)
179 models[name]["distance"][level] = len(delta)
180 models[name]["delta"][level] = delta
181
182def print_uarch_abi_csv():
183 print("# Automatically generated from '%s'" % __file__)
184 print("Model,baseline,v2,v3,v4")
185 for name in models.keys():
186 print(name, end="")
187 for level in range(len(levels)):
188 if models[name]["levels"][level]:
189 print(",✅", end="")
190 else:
191 print(",", end="")
192 print()
193
194print_uarch_abi_csv()