mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-07-31 14:07:16 +00:00
cpu-gather: Merge cpu-cpuid.py
Old usage: cpu-cpuid.py diff FILE... New usage: cpu-gather.py diff FILE... Signed-off-by: Tim Wiederhake <twiederh@redhat.com> Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
parent
bd05de35ef
commit
a42adc2714
@ -1,151 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import xml.etree.ElementTree
|
|
||||||
|
|
||||||
|
|
||||||
_KEYS = {
|
|
||||||
"cpuid": ["eax_in", "ecx_in"],
|
|
||||||
"msr": ["index"],
|
|
||||||
}
|
|
||||||
|
|
||||||
_REGS = {
|
|
||||||
"cpuid": ["eax", "ebx", "ecx", "edx"],
|
|
||||||
"msr": ["eax", "edx"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def checkFeature(cpuData, feature):
|
|
||||||
for key in ["type"] + _KEYS.get(feature["type"], list()):
|
|
||||||
if feature[key] not in cpuData:
|
|
||||||
return False
|
|
||||||
cpuData = cpuData[feature[key]]
|
|
||||||
|
|
||||||
for reg in _REGS.get(feature["type"], list()):
|
|
||||||
if feature[reg] > 0 and feature[reg] == feature[reg] & cpuData[reg]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def addFeature(cpuData, feature):
|
|
||||||
for key in ["type"] + _KEYS.get(feature["type"], list()):
|
|
||||||
if feature[key] not in cpuData:
|
|
||||||
cpuData[feature[key]] = dict()
|
|
||||||
cpuData = cpuData[feature[key]]
|
|
||||||
|
|
||||||
for reg in _REGS.get(feature["type"], list()):
|
|
||||||
cpuData[reg] = cpuData.get(reg, 0) | feature[reg]
|
|
||||||
|
|
||||||
|
|
||||||
def parseQemu(path, features):
|
|
||||||
cpuData = {}
|
|
||||||
with open(path, "r") as f:
|
|
||||||
data, pos = json.JSONDecoder().raw_decode(f.read())
|
|
||||||
|
|
||||||
for (prop, val) in data["return"]["model"]["props"].items():
|
|
||||||
if val and prop in features:
|
|
||||||
addFeature(cpuData, features[prop])
|
|
||||||
|
|
||||||
return cpuData
|
|
||||||
|
|
||||||
|
|
||||||
def parseCPUData(path):
|
|
||||||
cpuData = dict()
|
|
||||||
for f in xml.etree.ElementTree.parse(path).getroot():
|
|
||||||
if f.tag not in ("cpuid", "msr"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
feature = {"type": f.tag}
|
|
||||||
for reg in _KEYS[f.tag] + _REGS[f.tag]:
|
|
||||||
feature[reg] = int(f.attrib.get(reg, "0"), 0)
|
|
||||||
addFeature(cpuData, feature)
|
|
||||||
return cpuData
|
|
||||||
|
|
||||||
|
|
||||||
def parseMap():
|
|
||||||
path = os.path.dirname(sys.argv[0])
|
|
||||||
path = os.path.join(path, "..", "..", "src", "cpu_map", "x86_features.xml")
|
|
||||||
|
|
||||||
cpuMap = dict()
|
|
||||||
for f in xml.etree.ElementTree.parse(path).getroot().iter("feature"):
|
|
||||||
if f[0].tag not in ("cpuid", "msr"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
feature = {"type": f[0].tag}
|
|
||||||
for reg in _KEYS[f[0].tag] + _REGS[f[0].tag]:
|
|
||||||
feature[reg] = int(f[0].attrib.get(reg, "0"), 0)
|
|
||||||
cpuMap[f.attrib["name"]] = feature
|
|
||||||
return cpuMap
|
|
||||||
|
|
||||||
|
|
||||||
def formatCPUData(cpuData, path, comment):
|
|
||||||
print(path)
|
|
||||||
with open(path, "w") as f:
|
|
||||||
f.write("<!-- " + comment + " -->\n")
|
|
||||||
f.write("<cpudata arch='x86'>\n")
|
|
||||||
|
|
||||||
cpuid = cpuData["cpuid"]
|
|
||||||
for eax_in in sorted(cpuid.keys()):
|
|
||||||
for ecx_in in sorted(cpuid[eax_in].keys()):
|
|
||||||
leaf = cpuid[eax_in][ecx_in]
|
|
||||||
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 % (
|
|
||||||
eax_in, ecx_in,
|
|
||||||
leaf["eax"], leaf["ebx"], leaf["ecx"], leaf["edx"]))
|
|
||||||
|
|
||||||
if "msr" in cpuData:
|
|
||||||
msr = cpuData["msr"]
|
|
||||||
for index in sorted(msr.keys()):
|
|
||||||
f.write(" <msr index='0x%x' edx='0x%08x' eax='0x%08x'/>\n" %
|
|
||||||
(index, msr[index]['edx'], msr[index]['eax']))
|
|
||||||
|
|
||||||
f.write("</cpudata>\n")
|
|
||||||
|
|
||||||
|
|
||||||
def diff(args):
|
|
||||||
cpuMap = parseMap()
|
|
||||||
|
|
||||||
for jsonFile in args.json_files:
|
|
||||||
cpuDataFile = jsonFile.replace(".json", ".xml")
|
|
||||||
enabledFile = jsonFile.replace(".json", "-enabled.xml")
|
|
||||||
disabledFile = jsonFile.replace(".json", "-disabled.xml")
|
|
||||||
|
|
||||||
cpuData = parseCPUData(cpuDataFile)
|
|
||||||
qemu = parseQemu(jsonFile, cpuMap)
|
|
||||||
|
|
||||||
enabled = dict()
|
|
||||||
disabled = dict()
|
|
||||||
for feature in cpuMap.values():
|
|
||||||
if checkFeature(qemu, feature):
|
|
||||||
addFeature(enabled, feature)
|
|
||||||
elif checkFeature(cpuData, feature):
|
|
||||||
addFeature(disabled, feature)
|
|
||||||
|
|
||||||
formatCPUData(enabled, enabledFile, "Features enabled by QEMU")
|
|
||||||
formatCPUData(disabled, disabledFile, "Features disabled by QEMU")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description="Diff cpuid results")
|
|
||||||
subparsers = parser.add_subparsers(dest="action", required=True)
|
|
||||||
diffparser = subparsers.add_parser(
|
|
||||||
"diff",
|
|
||||||
help="Diff json description of CPU model against known features.")
|
|
||||||
diffparser.add_argument(
|
|
||||||
"json_files",
|
|
||||||
nargs="+",
|
|
||||||
metavar="FILE",
|
|
||||||
type=os.path.realpath,
|
|
||||||
help="Path to one or more json CPU model descriptions.")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
diff(args)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -8,6 +8,18 @@ import re
|
|||||||
import struct
|
import struct
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
|
|
||||||
|
_KEYS = {
|
||||||
|
"cpuid": ["eax_in", "ecx_in"],
|
||||||
|
"msr": ["index"],
|
||||||
|
}
|
||||||
|
|
||||||
|
_REGS = {
|
||||||
|
"cpuid": ["eax", "ebx", "ecx", "edx"],
|
||||||
|
"msr": ["eax", "edx"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def gather_name(args):
|
def gather_name(args):
|
||||||
@ -304,6 +316,118 @@ def parse(args, data):
|
|||||||
args.json_files = getattr(args, "json_files", list()) + [filename_json]
|
args.json_files = getattr(args, "json_files", list()) + [filename_json]
|
||||||
|
|
||||||
|
|
||||||
|
def checkFeature(cpuData, feature):
|
||||||
|
for key in ["type"] + _KEYS.get(feature["type"], list()):
|
||||||
|
if feature[key] not in cpuData:
|
||||||
|
return False
|
||||||
|
cpuData = cpuData[feature[key]]
|
||||||
|
|
||||||
|
for reg in _REGS.get(feature["type"], list()):
|
||||||
|
if feature[reg] > 0 and feature[reg] == feature[reg] & cpuData[reg]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def addFeature(cpuData, feature):
|
||||||
|
for key in ["type"] + _KEYS.get(feature["type"], list()):
|
||||||
|
if feature[key] not in cpuData:
|
||||||
|
cpuData[feature[key]] = dict()
|
||||||
|
cpuData = cpuData[feature[key]]
|
||||||
|
|
||||||
|
for reg in _REGS.get(feature["type"], list()):
|
||||||
|
cpuData[reg] = cpuData.get(reg, 0) | feature[reg]
|
||||||
|
|
||||||
|
|
||||||
|
def parseQemu(path, features):
|
||||||
|
cpuData = {}
|
||||||
|
with open(path, "r") as f:
|
||||||
|
data, pos = json.JSONDecoder().raw_decode(f.read())
|
||||||
|
|
||||||
|
for (prop, val) in data["return"]["model"]["props"].items():
|
||||||
|
if val and prop in features:
|
||||||
|
addFeature(cpuData, features[prop])
|
||||||
|
|
||||||
|
return cpuData
|
||||||
|
|
||||||
|
|
||||||
|
def parseCPUData(path):
|
||||||
|
cpuData = dict()
|
||||||
|
for f in xml.etree.ElementTree.parse(path).getroot():
|
||||||
|
if f.tag not in ("cpuid", "msr"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
feature = {"type": f.tag}
|
||||||
|
for reg in _KEYS[f.tag] + _REGS[f.tag]:
|
||||||
|
feature[reg] = int(f.attrib.get(reg, "0"), 0)
|
||||||
|
addFeature(cpuData, feature)
|
||||||
|
return cpuData
|
||||||
|
|
||||||
|
|
||||||
|
def parseMap():
|
||||||
|
path = os.path.dirname(sys.argv[0])
|
||||||
|
path = os.path.join(path, "..", "..", "src", "cpu_map", "x86_features.xml")
|
||||||
|
|
||||||
|
cpuMap = dict()
|
||||||
|
for f in xml.etree.ElementTree.parse(path).getroot().iter("feature"):
|
||||||
|
if f[0].tag not in ("cpuid", "msr"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
feature = {"type": f[0].tag}
|
||||||
|
for reg in _KEYS[f[0].tag] + _REGS[f[0].tag]:
|
||||||
|
feature[reg] = int(f[0].attrib.get(reg, "0"), 0)
|
||||||
|
cpuMap[f.attrib["name"]] = feature
|
||||||
|
return cpuMap
|
||||||
|
|
||||||
|
|
||||||
|
def formatCPUData(cpuData, path, comment):
|
||||||
|
print(path)
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write("<!-- " + comment + " -->\n")
|
||||||
|
f.write("<cpudata arch='x86'>\n")
|
||||||
|
|
||||||
|
cpuid = cpuData["cpuid"]
|
||||||
|
for eax_in in sorted(cpuid.keys()):
|
||||||
|
for ecx_in in sorted(cpuid[eax_in].keys()):
|
||||||
|
leaf = cpuid[eax_in][ecx_in]
|
||||||
|
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 % (
|
||||||
|
eax_in, ecx_in,
|
||||||
|
leaf["eax"], leaf["ebx"], leaf["ecx"], leaf["edx"]))
|
||||||
|
|
||||||
|
if "msr" in cpuData:
|
||||||
|
msr = cpuData["msr"]
|
||||||
|
for index in sorted(msr.keys()):
|
||||||
|
f.write(" <msr index='0x%x' edx='0x%08x' eax='0x%08x'/>\n" %
|
||||||
|
(index, msr[index]['edx'], msr[index]['eax']))
|
||||||
|
|
||||||
|
f.write("</cpudata>\n")
|
||||||
|
|
||||||
|
|
||||||
|
def diff(args):
|
||||||
|
cpuMap = parseMap()
|
||||||
|
|
||||||
|
for jsonFile in args.json_files:
|
||||||
|
cpuDataFile = jsonFile.replace(".json", ".xml")
|
||||||
|
enabledFile = jsonFile.replace(".json", "-enabled.xml")
|
||||||
|
disabledFile = jsonFile.replace(".json", "-disabled.xml")
|
||||||
|
|
||||||
|
cpuData = parseCPUData(cpuDataFile)
|
||||||
|
qemu = parseQemu(jsonFile, cpuMap)
|
||||||
|
|
||||||
|
enabled = dict()
|
||||||
|
disabled = dict()
|
||||||
|
for feature in cpuMap.values():
|
||||||
|
if checkFeature(qemu, feature):
|
||||||
|
addFeature(enabled, feature)
|
||||||
|
elif checkFeature(cpuData, feature):
|
||||||
|
addFeature(disabled, feature)
|
||||||
|
|
||||||
|
formatCPUData(enabled, enabledFile, "Features enabled by QEMU")
|
||||||
|
formatCPUData(disabled, disabledFile, "Features disabled by QEMU")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Gather cpu test data")
|
parser = argparse.ArgumentParser(description="Gather cpu test data")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -332,6 +456,15 @@ def main():
|
|||||||
subparsers.add_parser(
|
subparsers.add_parser(
|
||||||
"full",
|
"full",
|
||||||
help="Equivalent to `cpu-gather gather | cpu-gather parse`.")
|
help="Equivalent to `cpu-gather gather | cpu-gather parse`.")
|
||||||
|
diffparser = subparsers.add_parser(
|
||||||
|
"diff",
|
||||||
|
help="Diff json description of CPU model against known features.")
|
||||||
|
diffparser.add_argument(
|
||||||
|
"json_files",
|
||||||
|
nargs="+",
|
||||||
|
metavar="FILE",
|
||||||
|
type=os.path.realpath,
|
||||||
|
help="Path to one or more json CPU model descriptions.")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -359,9 +492,7 @@ def main():
|
|||||||
parse(args, data)
|
parse(args, data)
|
||||||
|
|
||||||
if "json_files" in args:
|
if "json_files" in args:
|
||||||
cmd = ["./cpu-cpuid.py", "diff"]
|
diff(args)
|
||||||
cmd.extend(args.json_files)
|
|
||||||
subprocess.check_call(cmd, universal_newlines=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
Reference in New Issue
Block a user