mirror of
https://github.com/andreas-abel/nanoBench.git
synced 2025-12-16 11:30:07 +01:00
benchmarks
This commit is contained in:
174
tools/cpuBench/addAMDDocToXML.py
Executable file
174
tools/cpuBench/addAMDDocToXML.py
Executable file
@@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
from collections import namedtuple
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
from openpyxl import load_workbook
|
||||||
|
|
||||||
|
DocEntry = namedtuple('DocEntry', ['mnemonic', 'operands', 'ops', 'unit', 'lat', 'tp'])
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Add data to XML file from AMD's doc")
|
||||||
|
parser.add_argument('-xml')
|
||||||
|
parser.add_argument('-xlsx')
|
||||||
|
parser.add_argument('-outputXML')
|
||||||
|
parser.add_argument('-arch')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
docEntrySet = set()
|
||||||
|
mnemonicMap = dict()
|
||||||
|
|
||||||
|
wb = load_workbook(args.xlsx, data_only=True)
|
||||||
|
ws = wb.active
|
||||||
|
for row in ws.iter_rows(min_row=2, values_only=True):
|
||||||
|
mnemonicStr = row[0]
|
||||||
|
if not mnemonicStr: continue
|
||||||
|
|
||||||
|
if mnemonicStr.endswith('cc'):
|
||||||
|
mnemonics = [mnemonicStr.replace('cc', p) for p in ['B', 'BE', 'L', 'LE', 'NB', 'NBE', 'NL', 'NLE', 'NO', 'NP', 'NS', 'NZ', 'O', 'P', 'S', 'Z']]
|
||||||
|
else:
|
||||||
|
mnemonics = mnemonicStr.replace(' (near)', '').replace('cc', '').split('/')
|
||||||
|
|
||||||
|
for mnemonic in mnemonics:
|
||||||
|
if mnemonic in ['AAA', 'AAD', 'AAM', 'AAS', 'ARPL', 'BOUND', 'DAA', 'DAS', 'INTO', 'JCXZ', 'LDS', 'LES','POPA', 'POPAD', 'POPD', 'POPFD', 'PUSHA', 'PUSHAD', 'PUSHFD']:
|
||||||
|
# 32-bit instructions
|
||||||
|
continue
|
||||||
|
if mnemonic in ['CMPS', 'FCLEX', 'FINIT', 'FSAVE', 'FSTCW', 'FSTENV', 'FSTSW', 'INS', 'LODS', 'LOOPNZ', 'LOOPZ', 'MOVS', 'OUTS', 'PCLMULHQHQDQ', 'PCLMULHQLQDQ', 'PCLMULLQHQDQ', 'PCLMULLQLQDQ', 'RDPRU', 'SAL', 'SCAS', 'STOS', 'VGATHERDD', 'VGATHERDQ', 'VGATHERQD', 'VGATHERQQ','VPCLMULHQHQDQ', 'VPCLMULHQLQDQ', 'VPCLMULLQHQDQ', 'VPCLMULLQLQDQ', 'WAIT', 'XLATB']:
|
||||||
|
# missing in XED
|
||||||
|
continue
|
||||||
|
if mnemonic in ['INT1', 'JECXZ']:
|
||||||
|
# missing from XML file
|
||||||
|
continue
|
||||||
|
|
||||||
|
operands = row[1:5]
|
||||||
|
|
||||||
|
ops = row[7]
|
||||||
|
if ops == 'not supported':
|
||||||
|
continue
|
||||||
|
|
||||||
|
unit = row[8]
|
||||||
|
lat = row[9]
|
||||||
|
tp = row[10]
|
||||||
|
|
||||||
|
de = DocEntry(mnemonic, operands, ops, unit, lat, tp)
|
||||||
|
docEntrySet.add(de)
|
||||||
|
mnemonicMap.setdefault(mnemonic, []).append(de)
|
||||||
|
|
||||||
|
iclassAsmDict = dict()
|
||||||
|
|
||||||
|
root = ET.parse(args.xml).getroot()
|
||||||
|
for instrNode in root.iter('instruction'):
|
||||||
|
if instrNode.attrib.get('evex', '') == '1':
|
||||||
|
continue
|
||||||
|
if instrNode.attrib['extension'] == 'VAES':
|
||||||
|
continue
|
||||||
|
iclass = instrNode.attrib['iclass']
|
||||||
|
asm = instrNode.attrib['asm']
|
||||||
|
iclassAsmDict.setdefault(iclass, set()).add(instrNode)
|
||||||
|
iclassAsmDict.setdefault(re.sub('{.*} ', '', asm), set()).add(instrNode)
|
||||||
|
|
||||||
|
#for x in set(op for de in docList for op in de.operands):
|
||||||
|
# print x
|
||||||
|
|
||||||
|
xmlToDocDict = dict()
|
||||||
|
|
||||||
|
for de in sorted(docEntrySet):
|
||||||
|
if de.mnemonic not in iclassAsmDict:
|
||||||
|
print 'no XML entry found for ' + str(de)
|
||||||
|
|
||||||
|
xmlFound = False
|
||||||
|
for instrNode in iclassAsmDict[de.mnemonic]:
|
||||||
|
explXmlOperands = [op for op in instrNode.findall('./operand') if not op.attrib.get('suppressed', '') == '1' and not op.attrib.get('implicit', '') == '1']
|
||||||
|
docOperands = [op for op in de.operands if op is not None]
|
||||||
|
|
||||||
|
if (not docOperands and any(op.attrib['type'] == 'mem' for op in explXmlOperands) and
|
||||||
|
any(len(instrNode2.findall('./operand[@type="mem"]')) == 0 for instrNode2 in iclassAsmDict[de.mnemonic] if instrNode != instrNode2)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if docOperands and explXmlOperands and (len(explXmlOperands) != len(docOperands)):
|
||||||
|
if any(len(explXmlOperands) == len([op for op in de2.operands if op is not None]) for de2 in mnemonicMap[de.mnemonic] if de!=de2):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if docOperands and explXmlOperands:
|
||||||
|
xmlOperands = explXmlOperands
|
||||||
|
else:
|
||||||
|
xmlOperands = [op for op in instrNode.findall('./operand')]
|
||||||
|
|
||||||
|
invalid = False
|
||||||
|
for docOp, xmlOp in zip(docOperands, xmlOperands):
|
||||||
|
if de.mnemonic in ['CLZERO']: continue
|
||||||
|
if xmlOp.attrib['type'] == 'mem' and set(de.operands) == {None}:
|
||||||
|
invalid = True
|
||||||
|
break
|
||||||
|
if docOp is None: continue
|
||||||
|
if docOp in ['pntr16/mem16:16/32']: continue
|
||||||
|
|
||||||
|
if xmlOp.attrib['type'] == 'reg':
|
||||||
|
if docOp == 'segmentReg':
|
||||||
|
if xmlOp.attrib.get('implicit', '') == '1': continue
|
||||||
|
elif docOp in ['reg', 'reg/mem'] and xmlOp.attrib.get('implicit', '') != '1': continue
|
||||||
|
elif not 'MM' in xmlOp.text:
|
||||||
|
if docOp == 'Sti' and xmlOp.text.startswith('ST'): continue
|
||||||
|
if docOp == 'ax' and xmlOp.text == 'AX': continue
|
||||||
|
if 'width' in xmlOp.attrib and re.search('reg(\d+/)*' + xmlOp.attrib['width'], docOp) is not None: continue
|
||||||
|
else:
|
||||||
|
if 'mmx' in docOp and xmlOp.text.startswith('MM'): continue
|
||||||
|
if 'xmm' in docOp and xmlOp.text.startswith('XMM'): continue
|
||||||
|
if 'ymm' in docOp and xmlOp.text.startswith('YMM'): continue
|
||||||
|
elif xmlOp.attrib['type'] == 'mem':
|
||||||
|
if docOp in ['mem', 'reg/mem', 'xmm2/mem', 'vm32x']: continue
|
||||||
|
if re.search('mem(\d+/)*' + xmlOp.attrib['width'], docOp) is not None: continue
|
||||||
|
elif xmlOp.attrib['type'] in ['imm', 'relbr']:
|
||||||
|
if docOp in ['imm', 'imm`', 'CL/Imm', 'xmm3/imm']: continue
|
||||||
|
if re.search('imm(\d+/)*' + xmlOp.attrib['width'], docOp) is not None: continue
|
||||||
|
|
||||||
|
invalid = True
|
||||||
|
|
||||||
|
if invalid:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if instrNode in xmlToDocDict:
|
||||||
|
if (set(de.operands) != {None}) and (set(xmlToDocDict[instrNode].operands) == {None}):
|
||||||
|
xmlFound = True
|
||||||
|
xmlToDocDict[instrNode] = de
|
||||||
|
elif (set(de.operands) == {None}) and (set(xmlToDocDict[instrNode].operands) != {None}):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print 'duplicate entry for ' + instrNode.attrib['string'] + ' found: ' + str(list(xmlToDocDict[instrNode])) + ', ' + str(list(de))
|
||||||
|
else:
|
||||||
|
xmlFound = True
|
||||||
|
xmlToDocDict[instrNode] = de
|
||||||
|
|
||||||
|
if not xmlFound:
|
||||||
|
print 'no matching XML entry found for ' + str(de)
|
||||||
|
|
||||||
|
print 'Found data for ' + str(len(xmlToDocDict)) + ' instruction variants'
|
||||||
|
|
||||||
|
for instrNode, de in xmlToDocDict.items():
|
||||||
|
archNode = instrNode.find('./architecture[@name="{}"]'.format(args.arch))
|
||||||
|
if archNode is None:
|
||||||
|
archNode = ET.SubElement(instrNode, "architecture")
|
||||||
|
archNode.attrib['name'] = args.arch
|
||||||
|
|
||||||
|
docNode = ET.SubElement(archNode, "doc")
|
||||||
|
if de.ops: docNode.attrib['uops'] = str(de.ops)
|
||||||
|
if de.unit: docNode.attrib['ports'] = str(de.unit)
|
||||||
|
if de.lat and de.lat != '-': docNode.attrib['latency'] = str(de.lat)
|
||||||
|
if de.tp:
|
||||||
|
try:
|
||||||
|
if str(de.tp) == '0.33':
|
||||||
|
docNode.attrib['TP'] = '3.00'
|
||||||
|
else:
|
||||||
|
docNode.attrib['TP'] = format(1/float(de.tp), '.2f')
|
||||||
|
except ValueError:
|
||||||
|
docNode.attrib['TP'] = de.tp
|
||||||
|
|
||||||
|
with open(args.outputXML, "w") as f:
|
||||||
|
rough_string = ET.tostring(root, 'utf-8')
|
||||||
|
reparsed = minidom.parseString(rough_string)
|
||||||
|
f.write('\n'.join([line for line in reparsed.toprettyxml(indent=' '*2).split('\n') if line.strip()]))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
68
tools/cpuBench/addDocToXML.py
Executable file
68
tools/cpuBench/addDocToXML.py
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
from collections import namedtuple
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
DocEntry = namedtuple('DocEntry', ['iform', 'regsize', 'mask', 'tp', 'lat'])
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Add data to XML file from Intel's CSV doc")
|
||||||
|
parser.add_argument('-xml')
|
||||||
|
parser.add_argument('-csv')
|
||||||
|
parser.add_argument('-outputXML')
|
||||||
|
parser.add_argument('-arch')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
docDict = dict()
|
||||||
|
|
||||||
|
with open(args.csv, 'r') as f:
|
||||||
|
for i, line in enumerate(f):
|
||||||
|
if i > 0:
|
||||||
|
de = DocEntry(*line.strip().split(','))
|
||||||
|
docDict.setdefault(de.iform, []).append(de)
|
||||||
|
|
||||||
|
root = ET.parse(args.xml).getroot()
|
||||||
|
|
||||||
|
|
||||||
|
for instrNode in root.iter('instruction'):
|
||||||
|
iform = instrNode.attrib['iform']
|
||||||
|
|
||||||
|
if iform in docDict:
|
||||||
|
matchingDEs = set(docDict[iform])
|
||||||
|
|
||||||
|
if len(matchingDEs) > 1:
|
||||||
|
for de in list(matchingDEs):
|
||||||
|
if de.regsize != '-':
|
||||||
|
if not instrNode.findall('./operand[@type="reg"][@width="{}"]'.format(de.regsize)):
|
||||||
|
matchingDEs.remove(de)
|
||||||
|
|
||||||
|
for de in list(matchingDEs):
|
||||||
|
if 'mask' in instrNode.attrib:
|
||||||
|
if (instrNode.attrib['mask'] == '1' and de.mask == 'no') or (instrNode.attrib['mask'] == '0' and de.mask == 'yes'):
|
||||||
|
matchingDEs.remove(de)
|
||||||
|
|
||||||
|
if len(matchingDEs) == 0:
|
||||||
|
print 'No matching iform: ' + iform
|
||||||
|
elif len(matchingDEs) > 1:
|
||||||
|
print 'Multiple matching iforms: ' + iform
|
||||||
|
else:
|
||||||
|
de = next(iter(matchingDEs))
|
||||||
|
|
||||||
|
archNode = instrNode.find('./architecture[@name="{}"]'.format(args.arch))
|
||||||
|
if archNode is None:
|
||||||
|
archNode = ET.SubElement(instrNode, "architecture")
|
||||||
|
archNode.attrib['name'] = args.arch
|
||||||
|
|
||||||
|
docNode = ET.SubElement(archNode, "doc")
|
||||||
|
if de.tp: docNode.attrib['TP'] = de.tp
|
||||||
|
if de.lat: docNode.attrib['latency'] = de.lat
|
||||||
|
|
||||||
|
with open(args.outputXML, "w") as f:
|
||||||
|
rough_string = ET.tostring(root, 'utf-8')
|
||||||
|
reparsed = minidom.parseString(rough_string)
|
||||||
|
f.write('\n'.join([line for line in reparsed.toprettyxml(indent=' '*2).split('\n') if line.strip()]))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
211
tools/cpuBench/compareMeasurementsToOther.py
Executable file
211
tools/cpuBench/compareMeasurementsToOther.py
Executable file
@@ -0,0 +1,211 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Compare results')
|
||||||
|
parser.add_argument("-input", help="Input XML file", default='result.xml')
|
||||||
|
parser.add_argument("-arch", help="Consider only this architecture")
|
||||||
|
parser.add_argument("-ignoreLockRep", help="Ignore Instructions with lock and rep prefixes", action='store_true')
|
||||||
|
parser.add_argument("-verbose", help="Verbose mode", action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
root = ET.parse(args.input)
|
||||||
|
|
||||||
|
instrArchNodes = []
|
||||||
|
for instrNode in root.iter('instruction'):
|
||||||
|
if args.ignoreLockRep and ('LOCK_' in instrNode.attrib['iform'] or 'REP_' in instrNode.attrib['iform']): continue
|
||||||
|
archNode = instrNode.find('./architecture[@name="{}"]'.format(args.arch))
|
||||||
|
if archNode is not None:
|
||||||
|
instrArchNodes.append((instrNode, archNode))
|
||||||
|
|
||||||
|
nPortsMeasurementOnly = 0
|
||||||
|
nPortsOtherOnly = 0
|
||||||
|
nPortsBoth = 0
|
||||||
|
nPortsEq = 0
|
||||||
|
nPortsDiff = 0
|
||||||
|
|
||||||
|
nUopsMeasurementOnly = 0
|
||||||
|
nUopsOtherOnly = 0
|
||||||
|
nUopsBoth = 0
|
||||||
|
nUopsEq = 0
|
||||||
|
nUopsEqPortsEq = 0
|
||||||
|
nUopsEqPortsDiff = 0
|
||||||
|
nUopsDiff = 0
|
||||||
|
|
||||||
|
nLatMeasurementOnly = 0
|
||||||
|
nLatOtherOnly = 0
|
||||||
|
nLatBoth = 0
|
||||||
|
nLatUB = 0
|
||||||
|
nLatUBCorrect = 0
|
||||||
|
nLatUBExact = 0
|
||||||
|
nLatUBClose = 0
|
||||||
|
nLatUBIncorrect = 0
|
||||||
|
nLatNoUB = 0
|
||||||
|
nLatNoUBMaxEq = 0
|
||||||
|
nLatNoUBMaxDiff = 0
|
||||||
|
|
||||||
|
for instrNode, archNode in instrArchNodes:
|
||||||
|
measurementNode = archNode.find('measurement')
|
||||||
|
nonMeasurementNodes = archNode.findall('./IACA') + archNode.findall('doc')
|
||||||
|
|
||||||
|
otherPorts = [v for m in nonMeasurementNodes for a,v in m.attrib.items() if a.startswith('ports')]
|
||||||
|
mPorts = ([v for a, v in measurementNode.attrib.items() if a.startswith('ports')] if measurementNode is not None else [])
|
||||||
|
|
||||||
|
portsEq = False
|
||||||
|
portsDiff = False
|
||||||
|
|
||||||
|
if mPorts:
|
||||||
|
if otherPorts:
|
||||||
|
nPortsBoth += 1
|
||||||
|
if any(m in otherPorts for m in mPorts):
|
||||||
|
portsEq = True
|
||||||
|
nPortsEq += 1
|
||||||
|
else:
|
||||||
|
portsDiff = True
|
||||||
|
nPortsDiff += 1
|
||||||
|
if args.verbose: print 'PortsDiff: {} - {} - {}'.format(instrNode.attrib['string'], mPorts, otherPorts)
|
||||||
|
else:
|
||||||
|
nPortsMeasurementOnly += 1
|
||||||
|
else:
|
||||||
|
if otherPorts:
|
||||||
|
nPortsOtherOnly += 1
|
||||||
|
if args.verbose: print 'PortsOtherOnly: ' + instrNode.attrib['string']
|
||||||
|
|
||||||
|
otherUops = [v for m in nonMeasurementNodes for a,v in m.attrib.items() if a.startswith('uops') and v.replace('.','',1).isdigit()]
|
||||||
|
mUops = ([v for a,v in measurementNode.attrib.items() if a.startswith('uops') and not 'retire_slots' in a] if measurementNode is not None else [])
|
||||||
|
|
||||||
|
if mUops:
|
||||||
|
if otherUops:
|
||||||
|
nUopsBoth += 1
|
||||||
|
if any(m in otherUops for m in mUops):
|
||||||
|
nUopsEq += 1
|
||||||
|
nUopsEqPortsEq += int(portsEq)
|
||||||
|
nUopsEqPortsDiff += int(portsDiff)
|
||||||
|
else:
|
||||||
|
nUopsDiff += 1
|
||||||
|
if args.verbose: print 'UopsDiff: {} - {} - {}'.format(instrNode.attrib['string'], mUops, otherUops)
|
||||||
|
else:
|
||||||
|
nUopsMeasurementOnly += 1
|
||||||
|
else:
|
||||||
|
if otherUops:
|
||||||
|
nUopsOtherOnly += 1
|
||||||
|
if args.verbose: print 'UopsOtherOnly: ' + instrNode.attrib['string']
|
||||||
|
|
||||||
|
|
||||||
|
otherLatencies = [float(v) for m in nonMeasurementNodes for a,v in m.attrib.items() if a.startswith('latency') and v.replace('.','',1).isdigit()]
|
||||||
|
|
||||||
|
latEntry = getLatencyTableEntry(measurementNode)
|
||||||
|
if latEntry is not None:
|
||||||
|
if otherLatencies:
|
||||||
|
nLatBoth += 1
|
||||||
|
_, _, _, maxLat, maxLatUB = latEntry
|
||||||
|
if maxLatUB:
|
||||||
|
nLatUB += 1
|
||||||
|
if any(x for x in otherLatencies if x <= maxLat):
|
||||||
|
nLatUBCorrect += 1
|
||||||
|
if maxLat in otherLatencies:
|
||||||
|
nLatUBExact += 1
|
||||||
|
diff = min(abs(float(maxLat)-float(o)) for o in otherLatencies)
|
||||||
|
if diff <= 1.01:
|
||||||
|
nLatUBClose += 1
|
||||||
|
else:
|
||||||
|
nLatUBIncorrect += 1
|
||||||
|
if args.verbose: print 'LatUBIncorrect: {} - {} - {}'.format(instrNode.attrib['string'], maxLat, otherLatencies)
|
||||||
|
else:
|
||||||
|
nLatNoUB += 1
|
||||||
|
if maxLat in otherLatencies:
|
||||||
|
nLatNoUBMaxEq += 1
|
||||||
|
else:
|
||||||
|
nLatNoUBMaxDiff += 1
|
||||||
|
if args.verbose: print 'LatNoUBMaxDiff: {} - {} - {}'.format(instrNode.attrib['string'], maxLat, otherLatencies)
|
||||||
|
else:
|
||||||
|
nLatMeasurementOnly += 1
|
||||||
|
else:
|
||||||
|
if otherLatencies:
|
||||||
|
nLatOtherOnly += 1
|
||||||
|
if args.verbose: print 'LatOtherOnly: ' + instrNode.attrib['string']
|
||||||
|
|
||||||
|
print 'Ports:'
|
||||||
|
print ' Measurement data only: ' + str(nPortsMeasurementOnly)
|
||||||
|
print ' Other data only: ' + str(nPortsOtherOnly)
|
||||||
|
print ' Both: ' + str(nPortsBoth)
|
||||||
|
print ' Eq: ' + str(nPortsEq)
|
||||||
|
print ' Diff: ' + str(nPortsDiff)
|
||||||
|
print ''
|
||||||
|
|
||||||
|
print 'Uops:'
|
||||||
|
print ' Measurement data only: ' + str(nUopsMeasurementOnly)
|
||||||
|
print ' Other data only: ' + str(nUopsOtherOnly)
|
||||||
|
print ' Both: ' + str(nUopsBoth)
|
||||||
|
print ' Eq: ' + str(nUopsEq)
|
||||||
|
print ' PortsEq: ' + str(nUopsEqPortsEq)
|
||||||
|
print ' PortsDiff: ' + str(nUopsEqPortsDiff)
|
||||||
|
print ' Diff: ' + str(nUopsDiff)
|
||||||
|
print ''
|
||||||
|
|
||||||
|
print 'Latency:'
|
||||||
|
print ' Measurement data only: ' + str(nLatMeasurementOnly)
|
||||||
|
print ' Other data only: ' + str(nLatOtherOnly)
|
||||||
|
print ' Both: ' + str(nLatBoth)
|
||||||
|
print ' Exact: ' + str(nLatNoUB)
|
||||||
|
print ' Eq (Max): ' + str(nLatNoUBMaxEq)
|
||||||
|
print ' Diff (Max): ' + str(nLatNoUBMaxDiff)
|
||||||
|
print ' Upper Bound: ' + str(nLatUB)
|
||||||
|
print ' Correct: ' + str(nLatUBCorrect)
|
||||||
|
print ' Exact: ' + str(nLatUBExact)
|
||||||
|
print ' Close: ' + str(nLatUBClose)
|
||||||
|
print ' Incorrect: ' + str(nLatUBIncorrect)
|
||||||
|
print ''
|
||||||
|
|
||||||
|
print 'Throughput:'
|
||||||
|
for TP_m, TP_o in [('TP', 'TP'), ('TP_ports', 'TP'), ('TP', 'TP_ports'), ('TP_ports', 'TP_ports')]:
|
||||||
|
nTPMeasurementOnly = 0
|
||||||
|
nTPOtherOnly = 0
|
||||||
|
nTPBoth = 0
|
||||||
|
nTPEq = 0
|
||||||
|
nTPDiff = 0
|
||||||
|
nTPClose = 0
|
||||||
|
nTPNotClose = 0
|
||||||
|
|
||||||
|
for instrNode, archNode in instrArchNodes:
|
||||||
|
measurementNode = archNode.find('measurement')
|
||||||
|
nonMeasurementNodes = archNode.findall('./IACA') + archNode.findall('doc')
|
||||||
|
|
||||||
|
otherTPs = [float(v) for m in nonMeasurementNodes for a,v in m.attrib.items() if a in [TP_o, TP_o+'_same_reg'] and v.replace('.','',1).isdigit()]
|
||||||
|
mTPs = ([float(v) for a, v in measurementNode.attrib.items() if a in [TP_m, TP_m+'_same_reg']] if measurementNode is not None else [])
|
||||||
|
|
||||||
|
if mTPs:
|
||||||
|
if otherTPs:
|
||||||
|
nTPBoth += 1
|
||||||
|
if any(m in otherTPs for m in mTPs):
|
||||||
|
nTPEq += 1
|
||||||
|
else:
|
||||||
|
nTPDiff += 1
|
||||||
|
if args.verbose: print 'TPDiff ({} (measurements) - {} (other)): {} - {} - {}'.format(TP_m, TP_o, instrNode.attrib['string'], mTPs, otherTPs)
|
||||||
|
diff = min(abs(float(m)-float(o)) for o in otherTPs for m in mTPs)
|
||||||
|
if diff <= .1:
|
||||||
|
nTPClose += 1
|
||||||
|
else:
|
||||||
|
nTPNotClose += 1
|
||||||
|
if args.verbose: print 'TPNotClose ({} (measurements) - {} (other)): {} - {} - {}'.format(TP_m, TP_o, instrNode.attrib['string'], mTPs, otherTPs)
|
||||||
|
else:
|
||||||
|
nTPMeasurementOnly += 1
|
||||||
|
else:
|
||||||
|
if otherTPs:
|
||||||
|
nTPOtherOnly += 1
|
||||||
|
if args.verbose: print 'TPOtherOnly ({} (measurements) - {} (other)): {}'.format(TP_m, TP_o, instrNode.attrib['string'])
|
||||||
|
|
||||||
|
print ' {} (measurements) - {} (other):'.format(TP_m, TP_o)
|
||||||
|
print ' Measurement data only: ' + str(nTPMeasurementOnly)
|
||||||
|
print ' Other data only: ' + str(nTPOtherOnly)
|
||||||
|
print ' Both: ' + str(nTPBoth)
|
||||||
|
print ' Eq: ' + str(nTPEq)
|
||||||
|
print ' Diff: ' + str(nTPDiff)
|
||||||
|
print ' Close: ' + str(nTPClose)
|
||||||
|
print ' NotClose: ' + str(nTPNotClose)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
81
tools/cpuBench/compareXML.py
Executable file
81
tools/cpuBench/compareXML.py
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# Shows the differences between two XML files for a specific microarchitecture
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Compare XML files')
|
||||||
|
parser.add_argument('inp1')
|
||||||
|
parser.add_argument('arch1')
|
||||||
|
parser.add_argument('inp2')
|
||||||
|
parser.add_argument('arch2')
|
||||||
|
parser.add_argument('-TP', action='store_true')
|
||||||
|
parser.add_argument('-lat', action='store_true')
|
||||||
|
parser.add_argument('-ports', action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
root1 = ET.parse(args.inp1).getroot()
|
||||||
|
root2 = ET.parse(args.inp2).getroot()
|
||||||
|
|
||||||
|
instrNodeDict1 = {instrNode.attrib['string']: instrNode for instrNode in root1.iter('instruction')}
|
||||||
|
instrNodeDict2 = {instrNode.attrib['string']: instrNode for instrNode in root2.iter('instruction')}
|
||||||
|
|
||||||
|
tpDiff = 0
|
||||||
|
latDiff = 0
|
||||||
|
portsDiff = 0
|
||||||
|
|
||||||
|
for instrStr in sorted(instrNodeDict1):
|
||||||
|
instrNode1 = instrNodeDict1[instrStr]
|
||||||
|
if not instrStr in instrNodeDict2:
|
||||||
|
print 'No matching entry found for ' + instrStr
|
||||||
|
continue
|
||||||
|
instrNode2 = instrNodeDict2[instrStr]
|
||||||
|
for mNode1 in instrNode1.findall('./architecture[@name="' + args.arch1 + '"]/measurement'):
|
||||||
|
for mNode2 in instrNode2.findall('./architecture[@name="' + args.arch2 + '"]/measurement'):
|
||||||
|
if args.TP:
|
||||||
|
tp1 = mNode1.attrib['TP']
|
||||||
|
tp2 = mNode2.attrib['TP']
|
||||||
|
if tp1 != tp2:
|
||||||
|
tpDiff += 1
|
||||||
|
print instrStr + ' - TP1: ' + tp1 + ' - TP2: ' + tp2
|
||||||
|
|
||||||
|
if args.lat:
|
||||||
|
for latNode1, latNode2 in zip(mNode1.findall('./latency'), mNode2.findall('./latency')):
|
||||||
|
latStr1 = ET.tostring(latNode1, encoding='utf-8').strip()
|
||||||
|
latStr2 = ET.tostring(latNode2, encoding='utf-8').strip()
|
||||||
|
if latStr1 != latStr2:
|
||||||
|
latDiff += 1
|
||||||
|
print instrStr
|
||||||
|
print ' ' + latStr1
|
||||||
|
print ' ' + latStr2
|
||||||
|
|
||||||
|
if args.ports:
|
||||||
|
p1 = mNode1.attrib.get('ports', '')
|
||||||
|
p2 = mNode2.attrib.get('ports', '')
|
||||||
|
if p1 != p2:
|
||||||
|
portsDiff += 1
|
||||||
|
print instrStr + ' - P1: ' + p1 + ' - P2: ' + p2
|
||||||
|
|
||||||
|
if not args.TP and not args.lat and not args.ports:
|
||||||
|
xmlStr1 = ET.tostring(mNode1, encoding='utf-8').strip()
|
||||||
|
xmlStr2 = ET.tostring(mNode2, encoding='utf-8').strip()
|
||||||
|
|
||||||
|
if xmlStr1 != xmlStr2:
|
||||||
|
print '-------------------------------'
|
||||||
|
print instrStr
|
||||||
|
print xmlStr1
|
||||||
|
print xmlStr2
|
||||||
|
print '-------------------------------'
|
||||||
|
|
||||||
|
if args.TP:
|
||||||
|
print 'TPDiff: ' + str(tpDiff)
|
||||||
|
|
||||||
|
if args.lat:
|
||||||
|
print 'LatDiff: ' + str(latDiff)
|
||||||
|
|
||||||
|
if args.ports:
|
||||||
|
print 'portsDiff: ' + str(portsDiff)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
3099
tools/cpuBench/cpuBench.py
Executable file
3099
tools/cpuBench/cpuBench.py
Executable file
File diff suppressed because it is too large
Load Diff
42
tools/cpuBench/mergeXML.py
Executable file
42
tools/cpuBench/mergeXML.py
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
# If inp2 contains a measurement node for an architecture for which inp1 does not contain a measurement node, the node is added to a copy of inp1.
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Merge XML files')
|
||||||
|
parser.add_argument('inp1')
|
||||||
|
parser.add_argument('inp2')
|
||||||
|
parser.add_argument('outp')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
root1 = ET.parse(args.inp1).getroot()
|
||||||
|
root2 = ET.parse(args.inp2).getroot()
|
||||||
|
instrNode2Dict = {instrNode.attrib['string']: instrNode for instrNode in root2.iter('instruction')}
|
||||||
|
|
||||||
|
root1.attrib['date'] = str(datetime.date.today())
|
||||||
|
|
||||||
|
for instrNode1 in root1.iter('instruction'):
|
||||||
|
if instrNode1.attrib['string'] not in instrNode2Dict:
|
||||||
|
print 'no matching entry found for ' + instrNode1.attrib['string']
|
||||||
|
continue
|
||||||
|
for instrNode2 in instrNode2Dict[instrNode1.attrib['string']]:
|
||||||
|
for archNode2 in instrNode2.iter('architecture'):
|
||||||
|
archNode1 = instrNode1.find('./architecture[@name="' + archNode2.attrib['name'] + '"]')
|
||||||
|
if archNode1 is not None:
|
||||||
|
if archNode1.findall('./measurement'): continue
|
||||||
|
for measurementNode in archNode2.findall('./measurement'):
|
||||||
|
archNode1.append(measurementNode)
|
||||||
|
else:
|
||||||
|
instrNode1.append(archNode2)
|
||||||
|
|
||||||
|
with open(args.outp, "w") as f:
|
||||||
|
rough_string = ET.tostring(root1, 'utf-8')
|
||||||
|
reparsed = minidom.parseString(rough_string)
|
||||||
|
f.write('\n'.join([line for line in reparsed.toprettyxml(indent=' '*2).split('\n') if line.strip()]))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
198
tools/cpuBench/utils.py
Executable file
198
tools/cpuBench/utils.py
Executable file
@@ -0,0 +1,198 @@
|
|||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from scipy.optimize import linprog
|
||||||
|
|
||||||
|
def addHTMLCodeForOperands(instrNode, html):
|
||||||
|
if instrNode.find('operand') is not None:
|
||||||
|
html.append('<h2>Operands</h2>')
|
||||||
|
html.append('<ul>')
|
||||||
|
for opNode in instrNode.iter('operand'):
|
||||||
|
line = 'Operand ' + opNode.attrib['idx']
|
||||||
|
properties = []
|
||||||
|
for prop in ['r', 'w']:
|
||||||
|
if opNode.attrib.get(prop, '0') == '1': properties.append(prop)
|
||||||
|
if properties: properties = ['/'.join(properties)]
|
||||||
|
if opNode.attrib.get('undef', '0') == '1': properties.append('undefined')
|
||||||
|
if opNode.attrib.get('suppressed', '0') == '1': properties.append('suppressed')
|
||||||
|
if opNode.attrib.get('optional', '0') == '1': properties.append('optional')
|
||||||
|
line += ' (' + ', '.join(properties) + '): '
|
||||||
|
if opNode.attrib['type'] == 'reg':
|
||||||
|
line += 'Register (' + opNode.text.replace(',', ', ') + ')'
|
||||||
|
elif opNode.attrib['type'] == 'mem':
|
||||||
|
line += 'Memory'
|
||||||
|
if 'asm-prefix' in opNode.attrib: line.append(' (' + opNode.attrib['asm-prefix'] + ')')
|
||||||
|
elif opNode.attrib['type'] == 'flags':
|
||||||
|
line += 'Flags ('
|
||||||
|
first = True
|
||||||
|
for k, v in opNode.attrib.items():
|
||||||
|
if k.startswith('flag_'):
|
||||||
|
if not first: line += ', '
|
||||||
|
line += k[5:] + ': ' + v
|
||||||
|
first = False
|
||||||
|
line += ')'
|
||||||
|
elif opNode.attrib['type'] == 'imm':
|
||||||
|
line += opNode.attrib['width'] + '-bit immediate'
|
||||||
|
if opNode.attrib.get('implicit', '') == '1':
|
||||||
|
line += ' (implicit): ' + opNode.text
|
||||||
|
html.append('<li>' + line + '</li>')
|
||||||
|
html.append('</ul>')
|
||||||
|
|
||||||
|
def canonicalizeInstrString(instrString):
|
||||||
|
return re.sub('[(){}, ]+', '_', instrString).strip('_')
|
||||||
|
|
||||||
|
def getTP_LP(PU):
|
||||||
|
if len(PU) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if len(PU) == 1:
|
||||||
|
pc, uops = PU[0]
|
||||||
|
return round(float(uops)/len(pc), 2)
|
||||||
|
|
||||||
|
ports = list(set.union(*[set(pc) for pc, _ in PU]))
|
||||||
|
|
||||||
|
zeroConstraint = []
|
||||||
|
for p in ports:
|
||||||
|
for pc, uops in PU:
|
||||||
|
if not p in pc:
|
||||||
|
zeroConstraint.append(1)
|
||||||
|
else:
|
||||||
|
zeroConstraint.append(0)
|
||||||
|
zeroConstraint.append(0) #z
|
||||||
|
|
||||||
|
nonZeroConstraints = []
|
||||||
|
nonZeroConstraintsRHS = []
|
||||||
|
for pu in PU:
|
||||||
|
pc, uops = pu
|
||||||
|
nonZeroConstraintsRHS.append(uops)
|
||||||
|
nonZeroConstraint = []
|
||||||
|
for p in ports:
|
||||||
|
for pu2 in PU:
|
||||||
|
if pu != pu2 or p not in pc:
|
||||||
|
nonZeroConstraint.append(0)
|
||||||
|
else:
|
||||||
|
nonZeroConstraint.append(1)
|
||||||
|
nonZeroConstraint.append(0) #z
|
||||||
|
nonZeroConstraints.append(nonZeroConstraint)
|
||||||
|
|
||||||
|
A_eq = [zeroConstraint] + nonZeroConstraints
|
||||||
|
b_eq = [0] + nonZeroConstraintsRHS
|
||||||
|
|
||||||
|
zConstraints = []
|
||||||
|
for p in ports:
|
||||||
|
zConstraint = []
|
||||||
|
for p2 in ports:
|
||||||
|
for pu in PU:
|
||||||
|
if p != p2:
|
||||||
|
zConstraint.append(0)
|
||||||
|
else:
|
||||||
|
zConstraint.append(1)
|
||||||
|
zConstraint.append(-1)
|
||||||
|
zConstraints.append(zConstraint)
|
||||||
|
|
||||||
|
A_ub = zConstraints
|
||||||
|
b_ub = [0] * len(zConstraints)
|
||||||
|
|
||||||
|
c = [0]*(len(PU)*len(ports)) + [1]
|
||||||
|
|
||||||
|
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq)
|
||||||
|
return round(res.fun, 2)
|
||||||
|
|
||||||
|
|
||||||
|
# Example output: "Latency operand 2 -> 1 (memory): <=3"
|
||||||
|
def latencyNodeToStr(latNode, sameReg, addr_mem):
|
||||||
|
suffix = ('_'+addr_mem if addr_mem else '') + ('_same_reg' if sameReg else '')
|
||||||
|
if not any((a in ['cycles'+suffix, 'min_cycles'+suffix]) for a in latNode.attrib):
|
||||||
|
return None
|
||||||
|
|
||||||
|
ret = 'Latency operand ' + latNode.attrib['start_op'] + ' → ' + latNode.attrib['target_op']
|
||||||
|
if sameReg:
|
||||||
|
ret += ', with the same register for different operands'
|
||||||
|
if addr_mem == 'addr':
|
||||||
|
ret += ' (address, base register)'
|
||||||
|
elif addr_mem == 'addr_VSIB':
|
||||||
|
ret += ' (address, index register)'
|
||||||
|
elif addr_mem == 'mem':
|
||||||
|
ret += ' (memory)'
|
||||||
|
ret += ': '
|
||||||
|
|
||||||
|
if 'cycles'+suffix in latNode.attrib:
|
||||||
|
if latNode.attrib.get('cycles'+suffix+'_is_upper_bound', '') == '1':
|
||||||
|
ret += '≤'
|
||||||
|
cycles = latNode.attrib['cycles'+suffix]
|
||||||
|
ret += cycles
|
||||||
|
else:
|
||||||
|
minCycles = latNode.attrib['min_cycles'+suffix]
|
||||||
|
maxCycles = latNode.attrib['max_cycles'+suffix]
|
||||||
|
|
||||||
|
if latNode.attrib.get('min_cycles'+suffix+'_is_upper_bound', '') == '1':
|
||||||
|
ret += '≤' + minCycles
|
||||||
|
else:
|
||||||
|
ret += minCycles + ' ≤ lat ≤ ' + maxCycles
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
# Returns (string, minLat, minLatUB, maxLat, maxLatUB)
|
||||||
|
# Example output: ("[1;<=7]", 1, False, 7, True)
|
||||||
|
def getLatencyTableEntry(measurementNode):
|
||||||
|
if measurementNode is None or measurementNode.find('./latency') is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
minLat = sys.maxint
|
||||||
|
maxLat = 0
|
||||||
|
minLatUB = False
|
||||||
|
maxLatUB = False
|
||||||
|
|
||||||
|
for latNode in measurementNode.findall('./latency'):
|
||||||
|
for sameReg in [False, True]:
|
||||||
|
for addr_mem in ['', 'addr', 'mem']:
|
||||||
|
suffix = ('_'+addr_mem if addr_mem else '') + ('_same_reg' if sameReg else '')
|
||||||
|
if 'cycles'+suffix in latNode.attrib:
|
||||||
|
cycles = int(latNode.attrib['cycles'+suffix])
|
||||||
|
isUB = (latNode.attrib.get('cycles'+suffix+'_is_upper_bound', '') == '1')
|
||||||
|
|
||||||
|
if cycles == maxLat:
|
||||||
|
maxLatUB = (maxLatUB and isUB)
|
||||||
|
elif cycles > maxLat:
|
||||||
|
maxLat = cycles
|
||||||
|
maxLatUB = isUB
|
||||||
|
|
||||||
|
if cycles == minLat:
|
||||||
|
minLatUB = (minLatUB or isUB)
|
||||||
|
elif cycles < minLat:
|
||||||
|
minLat = cycles
|
||||||
|
minLatUB = isUB
|
||||||
|
|
||||||
|
if 'max_cycles'+suffix in latNode.attrib:
|
||||||
|
cycles = int(latNode.attrib['max_cycles'+suffix])
|
||||||
|
isUB = (latNode.attrib.get('max_cycles'+suffix+'_is_upper_bound', '') == '1')
|
||||||
|
if cycles == maxLat:
|
||||||
|
maxLatUB = (maxLatUB and isUB)
|
||||||
|
elif cycles > maxLat:
|
||||||
|
maxLat = cycles
|
||||||
|
maxLatUB = isUB
|
||||||
|
|
||||||
|
if 'min_cycles'+suffix in latNode.attrib:
|
||||||
|
cycles = float(latNode.attrib['min_cycles'+suffix])
|
||||||
|
isUB = (latNode.attrib.get('min_cycles'+suffix+'_is_upper_bound', '') == '1')
|
||||||
|
if cycles == minLat:
|
||||||
|
minLatUB = (minLatUB or isUB)
|
||||||
|
elif cycles < minLat:
|
||||||
|
minLat = cycles
|
||||||
|
minLatUB = isUB
|
||||||
|
|
||||||
|
if minLat == maxLat:
|
||||||
|
latStr = str(maxLat)
|
||||||
|
if minLatUB or maxLatUB:
|
||||||
|
latStr = '≤' + latStr
|
||||||
|
else:
|
||||||
|
latStr = '['
|
||||||
|
if minLatUB:
|
||||||
|
latStr += '≤'
|
||||||
|
latStr += str(minLat)
|
||||||
|
latStr += ';'
|
||||||
|
if maxLatUB:
|
||||||
|
latStr += '≤'
|
||||||
|
latStr += str(maxLat)
|
||||||
|
latStr += ']'
|
||||||
|
|
||||||
|
return (latStr, minLat, minLatUB, maxLat, maxLatUB)
|
||||||
Reference in New Issue
Block a user