mirror of
https://github.com/andreas-abel/nanoBench.git
synced 2025-12-16 11:30:07 +01:00
support for other slices
This commit is contained in:
@@ -38,6 +38,7 @@ def main():
|
||||
parser.add_argument("-nMeasurements", help="Number of measurements", type=int, default=10)
|
||||
parser.add_argument("-agg", help="Aggregate function", default='med')
|
||||
parser.add_argument("-cBox", help="cBox (default: 1)", type=int, default=1)
|
||||
parser.add_argument("-slice", help="Slice (within the cBox) (default: 0)", type=int, default=0)
|
||||
parser.add_argument("-logLevel", help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)", default='WARNING')
|
||||
parser.add_argument("-blocks", help="Blocks to consider (default: all blocks in seq)")
|
||||
parser.add_argument("-maxAge", help="Maximum age", type=int)
|
||||
@@ -69,8 +70,9 @@ def main():
|
||||
title = 'Access Sequence: ' + args.seq.replace('?','').strip() + ' <n fresh blocks> <block>?'
|
||||
html.append(getPlotlyGraphDiv(title, '# of fresh blocks', 'Hits', traces))
|
||||
else:
|
||||
_, nbDict = getAgesOfBlocks(blocks, args.level, args.seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, clearHL=(not args.noClearHL),
|
||||
wbinvd=(not args.noWbinvd), returnNbResults=True, maxAge=args.maxAge, nMeasurements=args.nMeasurements, agg=args.agg)
|
||||
_, nbDict = getAgesOfBlocks(blocks, args.level, args.seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, cSlice=args.slice,
|
||||
clearHL=(not args.noClearHL), wbinvd=(not args.noWbinvd), returnNbResults=True, maxAge=args.maxAge,
|
||||
nMeasurements=args.nMeasurements, agg=args.agg)
|
||||
for event in sorted(e for e in nbDict.values()[0][0].keys() if 'HIT' in e or 'MISS' in e):
|
||||
traces = [(b, [nb[event] for nb in nbDict[b]]) for b in blocks]
|
||||
title = 'Access Sequence: ' + (args.seq_init + ' ' + args.seq).replace('?','').strip() + ' <n fresh blocks> <block>?'
|
||||
|
||||
@@ -282,7 +282,7 @@ def getCodeForAddressLists(codeAddressLists, initAddressLists=[], wbinvd=False,
|
||||
pfcEnabled = True
|
||||
|
||||
# use multiple lfence instructions to make sure that the block is actually in the cache and not still in a fill buffer
|
||||
codeList.append('lfence; ' * 10)
|
||||
codeList.append('lfence; ' * 25)
|
||||
|
||||
if addressList.flush:
|
||||
for address in addresses:
|
||||
@@ -353,7 +353,7 @@ def getClearHLAddresses(level, cacheSetList, cBox=1):
|
||||
return clearAddresses
|
||||
|
||||
L3SetToWayIDMap = dict()
|
||||
def getAddresses(level, wayID, cacheSetList, cBox=1, clearHL=True):
|
||||
def getAddresses(level, wayID, cacheSetList, cBox=1, cSlice=0, clearHL=True):
|
||||
lineSize = getCacheInfo(1).lineSize
|
||||
|
||||
if level <= 2 or (level == 3 and getCacheInfo(3).nSlices is None):
|
||||
@@ -363,20 +363,22 @@ def getAddresses(level, wayID, cacheSetList, cBox=1, clearHL=True):
|
||||
elif level == 3:
|
||||
if not cBox in L3SetToWayIDMap:
|
||||
L3SetToWayIDMap[cBox] = dict()
|
||||
if not cSlice in L3SetToWayIDMap[cBox]:
|
||||
L3SetToWayIDMap[cBox][cSlice] = dict()
|
||||
|
||||
addresses = []
|
||||
for L3Set in cacheSetList:
|
||||
if not L3Set in L3SetToWayIDMap[cBox]:
|
||||
L3SetToWayIDMap[cBox][L3Set] = dict()
|
||||
if not L3Set in L3SetToWayIDMap[cBox][cSlice]:
|
||||
L3SetToWayIDMap[cBox][cSlice][L3Set] = dict()
|
||||
if getCacheInfo(3).nSlices != getNCBoxUnits():
|
||||
for i, addr in enumerate(findMinimalL3EvictionSet(L3Set, cBox)):
|
||||
L3SetToWayIDMap[cBox][L3Set][i] = addr
|
||||
if not wayID in L3SetToWayIDMap[cBox][L3Set]:
|
||||
for i, addr in enumerate(findMinimalL3EvictionSet(L3Set, cBox, cSlice)):
|
||||
L3SetToWayIDMap[cBox][cSlice][L3Set][i] = addr
|
||||
if not wayID in L3SetToWayIDMap[cBox][cSlice][L3Set]:
|
||||
if getCacheInfo(3).nSlices == getNCBoxUnits():
|
||||
L3SetToWayIDMap[cBox][L3Set][wayID] = next(iter(getNewAddressesInCBox(1, cBox, L3Set, L3SetToWayIDMap[cBox][L3Set].values())))
|
||||
L3SetToWayIDMap[cBox][cSlice][L3Set][wayID] = next(iter(getNewAddressesInCBox(1, cBox, L3Set, L3SetToWayIDMap[cBox][cSlice][L3Set].values())))
|
||||
else:
|
||||
L3SetToWayIDMap[cBox][L3Set][wayID] = next(iter(findCongruentL3Addresses(1, L3Set, cBox, L3SetToWayIDMap[cBox][L3Set].values())))
|
||||
addresses.append(L3SetToWayIDMap[cBox][L3Set][wayID])
|
||||
L3SetToWayIDMap[cBox][cSlice][L3Set][wayID] = next(iter(findCongruentL3Addresses(1, L3Set, cBox, L3SetToWayIDMap[cBox][cSlice][L3Set].values())))
|
||||
addresses.append(L3SetToWayIDMap[cBox][cSlice][L3Set][wayID])
|
||||
|
||||
return addresses
|
||||
|
||||
@@ -436,7 +438,7 @@ def getAllUsedCacheSets(cacheSetList, seq, initSeq=''):
|
||||
|
||||
AddressList = namedtuple('AddressList', 'addresses exclude flush wbinvd')
|
||||
|
||||
def getCodeForCacheExperiment(level, seq, initSeq, cacheSetList, cBox, clearHL, wbinvd):
|
||||
def getCodeForCacheExperiment(level, seq, initSeq, cacheSetList, cBox, cSlice, clearHL, wbinvd):
|
||||
allUsedSets = getAllUsedCacheSets(cacheSetList, seq, initSeq)
|
||||
|
||||
clearHLAddrList = None
|
||||
@@ -461,7 +463,7 @@ def getCodeForCacheExperiment(level, seq, initSeq, cacheSetList, cBox, clearHL,
|
||||
flush = '!' in seqEl
|
||||
|
||||
s = [overrideSet] if overrideSet is not None else cacheSetList
|
||||
addresses = getAddresses(level, wayID, s, cBox=cBox, clearHL=clearHL)
|
||||
addresses = getAddresses(level, wayID, s, cBox=cBox, cSlice=cSlice, clearHL=clearHL)
|
||||
|
||||
if clearHLAddrList is not None and not flush:
|
||||
addrLists.append(clearHLAddrList)
|
||||
@@ -482,11 +484,12 @@ def runCacheExperimentCode(code, initCode, oneTimeInitCode, loop, warmUpCount, c
|
||||
|
||||
# cacheSets=None means do access in all sets
|
||||
# in this case, the first nL1Sets many sets of L2 will be reserved for clearing L1
|
||||
# cSlice refers to the nth slice within a given cBox; the assigment of numbers to slices is arbitrary
|
||||
# if wbinvd is set, wbinvd will be called before initSeq
|
||||
def runCacheExperiment(level, seq, initSeq='', cacheSets=None, cBox=1, clearHL=True, loop=1, wbinvd=False, nMeasurements=10, warmUpCount=1, codeSet=None,
|
||||
agg='avg'):
|
||||
def runCacheExperiment(level, seq, initSeq='', cacheSets=None, cBox=1, cSlice=0, clearHL=True, loop=1, wbinvd=False, nMeasurements=10, warmUpCount=1,
|
||||
codeSet=None, agg='avg'):
|
||||
cacheSetList = parseCacheSetsStr(level, clearHL, cacheSets)
|
||||
ec = getCodeForCacheExperiment(level, seq, initSeq=initSeq, cacheSetList=cacheSetList, cBox=cBox, clearHL=clearHL, wbinvd=wbinvd)
|
||||
ec = getCodeForCacheExperiment(level, seq, initSeq=initSeq, cacheSetList=cacheSetList, cBox=cBox, cSlice=cSlice, clearHL=clearHL, wbinvd=wbinvd)
|
||||
|
||||
log.debug('\nOneTimeInit: ' + ec.oneTimeInit)
|
||||
log.debug('\nInit: ' + ec.init)
|
||||
@@ -504,71 +507,69 @@ def printNB(nb_result):
|
||||
print r[0] + ': ' + str(r[1])
|
||||
|
||||
|
||||
def findMinimalL3EvictionSet(cacheSet, cBox):
|
||||
setNanoBenchParameters(config='\n'.join([getEventConfig('L3_HIT'), getEventConfig('L3_MISS')]), msrConfig=None, nMeasurements=10, unrollCount=1, loopCount=10,
|
||||
warmUpCount=None, initialWarmUpCount=None, aggregateFunction='med', basicMode=True, noMem=True, verbose=None)
|
||||
def hasL3Conflicts(addresses, clearHLAddrList, codeOffset):
|
||||
addrList = AddressList(addresses, False, False, False)
|
||||
ec = getCodeForAddressLists([clearHLAddrList, addrList], initAddressLists=[addrList], wbinvd=True)
|
||||
setNanoBenchParameters(config=getEventConfig('L3_HIT'), msrConfig='', nMeasurements=5, unrollCount=1, loopCount=100,
|
||||
aggregateFunction='med', basicMode=True, noMem=True, codeOffset=codeOffset)
|
||||
nb = runNanoBench(code=ec.code, init=ec.init, oneTimeInit=ec.oneTimeInit)
|
||||
|
||||
return (nb['L3_HIT'] < len(addresses) - .9)
|
||||
|
||||
|
||||
def findMinimalL3EvictionSet(cacheSet, cBox, cSlice):
|
||||
if not hasattr(findMinimalL3EvictionSet, 'evSetForCacheSet'):
|
||||
findMinimalL3EvictionSet.evSetForCacheSet = dict()
|
||||
if not cBox in findMinimalL3EvictionSet.evSetForCacheSet:
|
||||
findMinimalL3EvictionSet.evSetForCacheSet[cBox] = dict()
|
||||
evSetForCacheSet = findMinimalL3EvictionSet.evSetForCacheSet[cBox]
|
||||
if not cSlice in findMinimalL3EvictionSet.evSetForCacheSet[cBox]:
|
||||
findMinimalL3EvictionSet.evSetForCacheSet[cBox][cSlice] = dict()
|
||||
|
||||
if cacheSet in evSetForCacheSet:
|
||||
return evSetForCacheSet[cacheSet]
|
||||
if cacheSet in findMinimalL3EvictionSet.evSetForCacheSet[cBox][cSlice]:
|
||||
return findMinimalL3EvictionSet.evSetForCacheSet[cBox][cSlice][cacheSet]
|
||||
|
||||
evSetsForOtherSlices = [findMinimalL3EvictionSet(cacheSet, cBox, s) for s in range(0, cSlice)]
|
||||
|
||||
lineSize = getCacheInfo(1).lineSize
|
||||
L3Assoc = getCacheInfo(3).assoc
|
||||
L3WaySize = getCacheInfo(3).waySize
|
||||
|
||||
clearHLAddrList = AddressList(getClearHLAddresses(3, [cacheSet], cBox), True, False, False)
|
||||
codeOffset = lineSize * (cacheSet+10)
|
||||
|
||||
addresses = []
|
||||
curAddress = cacheSet*getCacheInfo(3).lineSize
|
||||
for curAddr in count(cacheSet * lineSize, L3WaySize):
|
||||
if any(curAddr in otherEvSet for otherEvSet in evSetsForOtherSlices): continue
|
||||
if not getCBoxOfAddress(curAddr) == cBox: continue
|
||||
if any(hasL3Conflicts(otherEvSet[:-1]+[curAddr], clearHLAddrList, codeOffset) for otherEvSet in evSetsForOtherSlices): continue
|
||||
|
||||
while len(addresses) < getCacheInfo(3).assoc:
|
||||
curAddress += getCacheInfo(3).waySize
|
||||
if getCBoxOfAddress(curAddress) == cBox:
|
||||
addresses.append(curAddress)
|
||||
|
||||
while True:
|
||||
curAddress += getCacheInfo(3).waySize
|
||||
if not getCBoxOfAddress(curAddress) == cBox: continue
|
||||
|
||||
addresses += [curAddress]
|
||||
ec = getCodeForAddressLists([AddressList(addresses, False, False, False), clearHLAddrList])
|
||||
|
||||
setNanoBenchParameters(config=getDefaultCacheConfig(), msrConfig='', nMeasurements=10, unrollCount=1, loopCount=100,
|
||||
aggregateFunction='med', basicMode=True, noMem=True)
|
||||
nb = runNanoBench(code=ec.code, oneTimeInit=ec.oneTimeInit)
|
||||
|
||||
if nb['L3_HIT'] < len(addresses) - .9:
|
||||
addresses.append(curAddr)
|
||||
if len(addresses) > L3Assoc and hasL3Conflicts(addresses, clearHLAddrList, codeOffset):
|
||||
break
|
||||
|
||||
for i in reversed(range(0, len(addresses))):
|
||||
if len(addresses) <= L3Assoc+1:
|
||||
break
|
||||
tmpAddresses = addresses[:i] + addresses[(i+1):]
|
||||
|
||||
ec = getCodeForAddressLists([AddressList(tmpAddresses, False, False, False), clearHLAddrList])
|
||||
nb = runNanoBench(code=ec.code, oneTimeInit=ec.oneTimeInit)
|
||||
|
||||
if nb['L3_HIT'] < len(tmpAddresses) - 0.9:
|
||||
if hasL3Conflicts(tmpAddresses, clearHLAddrList, codeOffset):
|
||||
addresses = tmpAddresses
|
||||
|
||||
evSetForCacheSet[cacheSet] = addresses
|
||||
findMinimalL3EvictionSet.evSetForCacheSet[cBox][cSlice][cacheSet] = addresses
|
||||
return addresses
|
||||
|
||||
|
||||
def findCongruentL3Addresses(n, cacheSet, cBox, L3EvictionSet):
|
||||
clearHLAddrList = AddressList(getClearHLAddresses(3, [cacheSet], cBox), True, False, False)
|
||||
|
||||
congrAddresses = []
|
||||
codeOffset = getCacheInfo(1).lineSize * (cacheSet+10)
|
||||
L3WaySize = getCacheInfo(3).waySize
|
||||
|
||||
congrAddresses = []
|
||||
for newAddr in count(max(L3EvictionSet)+L3WaySize, L3WaySize):
|
||||
if not getCBoxOfAddress(newAddr) == cBox: continue
|
||||
|
||||
tmpAddresses = L3EvictionSet[:getCacheInfo(3).assoc] + [newAddr]
|
||||
ec = getCodeForAddressLists([AddressList(tmpAddresses, False, False, False), clearHLAddrList])
|
||||
|
||||
setNanoBenchParameters(config=getEventConfig('L3_HIT'), msrConfig=None, nMeasurements=10, unrollCount=1, loopCount=100,
|
||||
aggregateFunction='med', basicMode=True, noMem=True, verbose=None)
|
||||
nb = runNanoBench(code=ec.code, oneTimeInit=ec.oneTimeInit)
|
||||
|
||||
if nb['L3_HIT'] < len(tmpAddresses) - 0.9:
|
||||
if hasL3Conflicts(tmpAddresses, clearHLAddrList, codeOffset):
|
||||
congrAddresses.append(newAddr)
|
||||
|
||||
if len(congrAddresses) >= n: break
|
||||
@@ -601,13 +602,8 @@ def findMaximalNonEvictingL3SetInCBox(start, stride, L3Assoc, cBox):
|
||||
continue
|
||||
|
||||
newAddresses = addresses + [curAddress]
|
||||
ec = getCodeForAddressLists([AddressList(newAddresses, False, False, False), clearHLAddrList])
|
||||
|
||||
setNanoBenchParameters(config=getEventConfig('L3_HIT'), msrConfig='', nMeasurements=10, unrollCount=1, loopCount=10,
|
||||
aggregateFunction='med', basicMode=True, noMem=True)
|
||||
nb = runNanoBench(code=ec.code, oneTimeInit=ec.oneTimeInit)
|
||||
|
||||
if nb['L3_HIT'] > len(newAddresses) - .9:
|
||||
if not hasL3Conflicts(newAddresses, clearHLAddrList, start+getCacheInfo(1).lineSize):
|
||||
addresses = newAddresses
|
||||
notAdded = 0
|
||||
else:
|
||||
@@ -628,7 +624,7 @@ def getUnusedBlockNames(n, usedBlockNames, prefix=''):
|
||||
|
||||
# Returns a dict with the age of each block, i.e., how many fresh blocks need to be accessed until the block is evicted
|
||||
# if returnNbResults is True, the function returns additionally all measurment results (as the second component of a tuple)
|
||||
def getAgesOfBlocks(blocks, level, seq, initSeq='', maxAge=None, cacheSets=None, cBox=1, clearHL=True, wbinvd=False, returnNbResults=False, nMeasurements=10, agg='avg'):
|
||||
def getAgesOfBlocks(blocks, level, seq, initSeq='', maxAge=None, cacheSets=None, cBox=1, cSlice=0, clearHL=True, wbinvd=False, returnNbResults=False, nMeasurements=10, agg='avg'):
|
||||
ages = dict()
|
||||
if returnNbResults: nbResults = dict()
|
||||
|
||||
@@ -645,7 +641,8 @@ def getAgesOfBlocks(blocks, level, seq, initSeq='', maxAge=None, cacheSets=None,
|
||||
newBlocks = getUnusedBlockNames(nNewBlocks, seq+initSeq, 'N')
|
||||
curSeq += ' '.join(newBlocks) + ' ' + block + '?'
|
||||
|
||||
nb = runCacheExperiment(level, curSeq, initSeq=initSeq, cacheSets=cacheSets, cBox=cBox, clearHL=clearHL, loop=0, wbinvd=wbinvd, nMeasurements=nMeasurements, agg=agg)
|
||||
nb = runCacheExperiment(level, curSeq, initSeq=initSeq, cacheSets=cacheSets, cBox=cBox, cSlice=cSlice, clearHL=clearHL, loop=0, wbinvd=wbinvd,
|
||||
nMeasurements=nMeasurements, agg=agg)
|
||||
if returnNbResults: nbResults[block].append(nb)
|
||||
|
||||
hitEvent = 'L' + str(level) + '_HIT'
|
||||
|
||||
@@ -19,6 +19,7 @@ def main():
|
||||
parser.add_argument("-level", help="Cache level (Default: 1)", type=int, default=1)
|
||||
parser.add_argument("-sets", help="Cache sets (if not specified, all cache sets are used)")
|
||||
parser.add_argument("-cBox", help="cBox (default: 1)", type=int, default=1) # use 1 as default, as, e.g., on SNB, box 0 only has 15 ways instead of 16
|
||||
parser.add_argument("-slice", help="Slice (within the cBox) (default: 0)", type=int, default=0)
|
||||
parser.add_argument("-noClearHL", help="Do not clear higher levels", action='store_true')
|
||||
parser.add_argument("-nMeasurements", help="Number of measurements", type=int, default=10)
|
||||
parser.add_argument("-agg", help="Aggregate function", default='med')
|
||||
@@ -37,8 +38,8 @@ def main():
|
||||
hits = cacheSim.getHits(seq, policyClass, args.simAssoc, args.sets) / args.loop
|
||||
print 'Hits: ' + str(hits)
|
||||
else:
|
||||
nb = runCacheExperiment(args.level, args.seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, clearHL=(not args.noClearHL), loop=args.loop,
|
||||
wbinvd=(not args.noWbinvd), nMeasurements=args.nMeasurements, agg=args.agg)
|
||||
nb = runCacheExperiment(args.level, args.seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, cSlice=args.slice, clearHL=(not args.noClearHL),
|
||||
loop=args.loop, wbinvd=(not args.noWbinvd), nMeasurements=args.nMeasurements, agg=args.agg)
|
||||
printNB(nb)
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ def main():
|
||||
parser.add_argument("-level", help="Cache level (Default: 1)", type=int, default=1)
|
||||
parser.add_argument("-sets", help="Cache sets (if not specified, all cache sets are used)")
|
||||
parser.add_argument("-cBox", help="cBox (default: 1)", type=int, default=1) # use 1 as default, as, e.g., on SNB, box 0 only has 15 ways instead of 16
|
||||
parser.add_argument("-slice", help="Slice (within the cBox) (default: 0)", type=int, default=0)
|
||||
parser.add_argument("-noClearHL", help="Do not clear higher levels", action='store_true')
|
||||
parser.add_argument("-loop", help="Loop count (Default: 1)", type=int, default=1)
|
||||
parser.add_argument("-noWbinvd", help="Do not call wbinvd before each run", action='store_true')
|
||||
@@ -39,8 +40,8 @@ def main():
|
||||
else:
|
||||
setCount = len(parseCacheSetsStr(args.level, True, args.sets))
|
||||
seq = re.sub('[?!]', '', args.seq).strip() + '?'
|
||||
nb = runCacheExperiment(args.level, seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, clearHL=(not args.noClearHL), loop=args.loop,
|
||||
wbinvd=(not args.noWbinvd))
|
||||
nb = runCacheExperiment(args.level, seq, initSeq=args.seq_init, cacheSets=args.sets, cBox=args.cBox, cSlice=args.slice, clearHL=(not args.noClearHL),
|
||||
loop=args.loop, wbinvd=(not args.noWbinvd))
|
||||
if nb['L' + str(args.level) + '_HIT']/setCount > .5:
|
||||
print 'HIT'
|
||||
exit(1)
|
||||
|
||||
@@ -20,7 +20,7 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def getPermutations(level, html, cacheSets=None, getInitialAges=True, maxAge=None, cBox=1):
|
||||
def getPermutations(level, html, cacheSets=None, getInitialAges=True, maxAge=None, cBox=1, cSlice=0):
|
||||
assoc = getCacheInfo(level).assoc
|
||||
if not maxAge:
|
||||
maxAge=2*assoc
|
||||
@@ -32,7 +32,8 @@ def getPermutations(level, html, cacheSets=None, getInitialAges=True, maxAge=Non
|
||||
initBlocks = ['I' + str(i) for i in range(0, assoc)]
|
||||
seq = ' '.join(initBlocks)
|
||||
|
||||
initAges, nbDict = getAgesOfBlocks(initBlocks, level, seq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge, cBox=cBox)
|
||||
initAges, nbDict = getAgesOfBlocks(initBlocks, level, seq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge,
|
||||
cBox=cBox, cSlice=cSlice)
|
||||
|
||||
accSeqStr = 'Access sequence: <wbinvd> ' + seq
|
||||
print accSeqStr
|
||||
@@ -47,7 +48,8 @@ def getPermutations(level, html, cacheSets=None, getInitialAges=True, maxAge=Non
|
||||
blocks = ['B' + str(i) for i in range(0, assoc)]
|
||||
baseSeq = ' '.join(initBlocks + blocks)
|
||||
|
||||
ages, nbDict = getAgesOfBlocks(blocks, level, baseSeq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge, cBox=cBox)
|
||||
ages, nbDict = getAgesOfBlocks(blocks, level, baseSeq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge,
|
||||
cBox=cBox, cSlice=cSlice)
|
||||
|
||||
accSeqStr = 'Access sequence: <wbinvd> ' + baseSeq
|
||||
print accSeqStr
|
||||
@@ -61,7 +63,8 @@ def getPermutations(level, html, cacheSets=None, getInitialAges=True, maxAge=Non
|
||||
|
||||
for permI, permBlock in enumerate(blocksSortedByAge):
|
||||
seq = baseSeq + ' ' + permBlock
|
||||
permAges, nbDict = getAgesOfBlocks(blocks, level, seq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge, cBox=cBox)
|
||||
permAges, nbDict = getAgesOfBlocks(blocks, level, seq, cacheSets=cacheSets, clearHL=True, wbinvd=True, returnNbResults=True, maxAge=maxAge,
|
||||
cBox=cBox, cSlice=cSlice)
|
||||
|
||||
accSeqStr = 'Access sequence: <wbinvd> ' + seq
|
||||
traces = [(b, [nb[event] for nb in nbDict[b]]) for b in blocks]
|
||||
@@ -84,6 +87,7 @@ def main():
|
||||
parser.add_argument("-noInit", help="Do not fill sets with associativity many elements first", action='store_true')
|
||||
parser.add_argument("-maxAge", help="Maximum age", type=int)
|
||||
parser.add_argument("-cBox", help="cBox (default: 1)", type=int, default=1)
|
||||
parser.add_argument("-slice", help="Slice (within the cBox) (default: 0)", type=int, default=0)
|
||||
parser.add_argument("-sim", help="Simulate the given policy instead of running the experiment on the hardware")
|
||||
parser.add_argument("-simAssoc", help="Associativity of the simulated cache (default: 8)", type=int, default=8)
|
||||
parser.add_argument("-logLevel", help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)", default='WARNING')
|
||||
@@ -97,7 +101,7 @@ def main():
|
||||
|
||||
html = ['<html>', '<head>', '<title>' + title + '</title>', '<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>', '</head>', '<body>']
|
||||
html += ['<h3>' + title + '</h3>']
|
||||
getPermutations(args.level, html, cacheSets=args.sets, getInitialAges=(not args.noInit), maxAge=args.maxAge, cBox=args.cBox)
|
||||
getPermutations(args.level, html, cacheSets=args.sets, getInitialAges=(not args.noInit), maxAge=args.maxAge, cBox=args.cBox, cSlice=args.slice)
|
||||
html += ['</body>', '</html>']
|
||||
|
||||
with open(args.output ,'w') as f:
|
||||
|
||||
@@ -12,16 +12,16 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def getActualHits(seq, level, cacheSets, cBox, nMeasurements=10):
|
||||
nb = runCacheExperiment(level, seq, cacheSets=cacheSets, cBox=cBox, clearHL=True, loop=1, wbinvd=True, nMeasurements=nMeasurements, agg='med')
|
||||
def getActualHits(seq, level, cacheSets, cBox, cSlice, nMeasurements=10):
|
||||
nb = runCacheExperiment(level, seq, cacheSets=cacheSets, cBox=cBox, cSlice=cSlice, clearHL=True, loop=1, wbinvd=True, nMeasurements=nMeasurements, agg='med')
|
||||
return int(nb['L' + str(level) + '_HIT']+0.1)
|
||||
|
||||
|
||||
def findSmallCounterexample(policy, initSeq, level, sets, cBox, assoc, seq, nMeasurements):
|
||||
def findSmallCounterexample(policy, initSeq, level, sets, cBox, cSlice, assoc, seq, nMeasurements):
|
||||
seqSplit = seq.split()
|
||||
for seqPrefix in [seqSplit[:i] for i in range(assoc+1, len(seqSplit)+1)]:
|
||||
seq = initSeq + ' '.join(seqPrefix)
|
||||
actual = getActualHits(seq, level, sets, cBox, nMeasurements)
|
||||
actual = getActualHits(seq, level, sets, cBox, cSlice, nMeasurements)
|
||||
sim = cacheSim.getHits(seq, cacheSim.AllPolicies[policy], assoc, sets)
|
||||
print 'seq:' + seq + ', actual: ' + str(actual) + ', sim: ' + str(sim)
|
||||
if sim != actual:
|
||||
@@ -30,7 +30,7 @@ def findSmallCounterexample(policy, initSeq, level, sets, cBox, assoc, seq, nMea
|
||||
for i in reversed(range(0, len(seqPrefix)-1)):
|
||||
tmpPrefix = seqPrefix[:i] + seqPrefix[(i+1):]
|
||||
seq = initSeq + ' '.join(tmpPrefix)
|
||||
actual = getActualHits(seq, level, sets, cBox, nMeasurements)
|
||||
actual = getActualHits(seq, level, sets, cBox, cSlice, nMeasurements)
|
||||
sim = cacheSim.getHits(seq, cacheSim.AllPolicies[policy], assoc, sets)
|
||||
print 'seq:' + seq + ', actual: ' + str(actual) + ', sim: ' + str(sim)
|
||||
if sim != actual:
|
||||
@@ -60,6 +60,7 @@ def main():
|
||||
parser.add_argument("-level", help="Cache level (Default: 1)", type=int, default=1)
|
||||
parser.add_argument("-sets", help="Cache sets (if not specified, all cache sets are used)")
|
||||
parser.add_argument("-cBox", help="cBox (default: 0)", type=int)
|
||||
parser.add_argument("-slice", help="Slice (within the cBox) (default: 0)", type=int, default=0)
|
||||
parser.add_argument("-nMeasurements", help="Number of measurements", type=int, default=3)
|
||||
parser.add_argument("-rep", help="Number of repetitions of each experiment (Default: 1)", type=int, default=1)
|
||||
parser.add_argument("-findCtrEx", help="Tries to find a small counterexample for each policy (only available for deterministic policies)", action='store_true')
|
||||
@@ -117,7 +118,7 @@ def main():
|
||||
print fullSeq
|
||||
|
||||
html += ['<tr><td>' + fullSeq + '</td>']
|
||||
actualHits = set([getActualHits(fullSeq, args.level, args.sets, cBox, args.nMeasurements) for _ in range(0, args.rep)])
|
||||
actualHits = set([getActualHits(fullSeq, args.level, args.sets, cBox, args.slice, args.nMeasurements) for _ in range(0, args.rep)])
|
||||
html += ['<td>' + ('{' if len(actualHits) > 1 else '') + ', '.join(map(str, sorted(actualHits))) + ('}' if len(actualHits) > 1 else '') + '</td>']
|
||||
|
||||
outp = ''
|
||||
@@ -130,8 +131,8 @@ def main():
|
||||
dists[p] += 1
|
||||
color = 'red'
|
||||
if args.findCtrEx and not p in counterExamples:
|
||||
counterExamples[p] = findSmallCounterexample(p, ((args.initSeq + ' ') if args.initSeq else ''), args.level, args.sets, cBox, assoc, seq,
|
||||
args.nMeasurements)
|
||||
counterExamples[p] = findSmallCounterexample(p, ((args.initSeq + ' ') if args.initSeq else ''), args.level, args.sets, cBox, args.slice,
|
||||
assoc, seq, args.nMeasurements)
|
||||
elif len(actualHits) > 1:
|
||||
color = 'yellow'
|
||||
else:
|
||||
|
||||
@@ -16,6 +16,8 @@ def main():
|
||||
parser.add_argument("-level", help="Cache level (Default: 3)", type=int, default=3)
|
||||
parser.add_argument("-nRuns", help="Maximum number of runs", type=int, default=25)
|
||||
parser.add_argument("-loop", help="Loop count", type=int, default=25)
|
||||
parser.add_argument("-length", help="Length of the acc. seq. (Default: associativity*4/3)", type=int)
|
||||
parser.add_argument("-noClearHL", help="Do not clear higher levels", action='store_true')
|
||||
parser.add_argument("-nMeasurements", help="Number of measurements", type=int, default=10)
|
||||
parser.add_argument("-output", help="Output file name", default='setDueling.html')
|
||||
parser.add_argument("-logLevel", help="Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)", default='INFO')
|
||||
@@ -27,64 +29,85 @@ def main():
|
||||
nSets = getCacheInfo(args.level).nSets
|
||||
lineSize = getCacheInfo(1).lineSize
|
||||
nCBoxes = max(1, getNCBoxUnits())
|
||||
seq = ' '.join('B' + str(i) + '?' for i in range(0, assoc*4/3))
|
||||
nSlicesPerCBox = 1
|
||||
if getCacheInfo(3).nSlices:
|
||||
nSlicesPerCBox = getCacheInfo(3).nSlices / getCacheInfo(3).nCboxes
|
||||
|
||||
title = cpuid.cpu_name(cpuid.CPUID()) + ', Level: ' + str(args.level)
|
||||
seqLength = (args.length if args.length is not None else assoc*4/3)
|
||||
seq = ' '.join('B' + str(i) + '?' for i in range(0, seqLength))
|
||||
hitSeq = ' '.join('B' + str(i) + '?' for i in range(0, assoc))
|
||||
missSeq = ' '.join('B' + str(i) + '?' for i in range(0, 3*assoc))
|
||||
|
||||
title = cpuid.cpu_name(cpuid.CPUID()) + ', L' + str(args.level) + ' Hits'
|
||||
html = ['<html>', '<head>', '<title>' + title + '</title>', '<script src="https://cdn.plot.ly/plotly-latest.min.js">', '</script>', '</head>', '<body>']
|
||||
html += ['<h3>' + title + '</h3>']
|
||||
|
||||
setsForCBox = {cBox: range(0,nSets) for cBox in range(0, nCBoxes)}
|
||||
yValuesForCBox = {cBox: [[] for s in range(0, nSets)] for cBox in range(0, nCBoxes)}
|
||||
setsForSlice = {cBox: {cSlice: range(0,nSets) for cSlice in range(0, nSlicesPerCBox)} for cBox in range(0, nCBoxes)}
|
||||
yValuesForSlice = {cBox: {cSlice: [[] for s in range(0, nSets)] for cSlice in range(0, nSlicesPerCBox)} for cBox in range(0, nCBoxes)}
|
||||
|
||||
prevOti = ''
|
||||
i = -1
|
||||
notChanged = -1
|
||||
prevEc = ExperimentCode('', '', '')
|
||||
|
||||
while notChanged < 10:
|
||||
i += 1
|
||||
notChanged += 1
|
||||
for useHitSeq in [False, True]:
|
||||
i += 1
|
||||
notChanged += 1
|
||||
for cBox in range(0, nCBoxes):
|
||||
for cSlice in range(0, nSlicesPerCBox):
|
||||
yValuesList = yValuesForSlice[cBox][cSlice]
|
||||
|
||||
for cBox in range(0, nCBoxes):
|
||||
yValuesList = yValuesForCBox[cBox]
|
||||
curSets = setsForSlice[cBox][cSlice]
|
||||
random.shuffle(curSets)
|
||||
prevSets = curSets[:]
|
||||
|
||||
curSets = setsForCBox[cBox]
|
||||
random.shuffle(curSets)
|
||||
prevSets = curSets[:]
|
||||
for si, s in enumerate(prevSets):
|
||||
codeSet = (s + random.randint(1, nSets - 100)) % nSets
|
||||
codeOffset = lineSize * codeSet
|
||||
yv = yValuesList[s]
|
||||
|
||||
for si, s in enumerate(prevSets):
|
||||
codeSet = (s + random.randint(1, nSets - 100)) % nSets
|
||||
codeOffset = lineSize * codeSet
|
||||
ec = getCodeForCacheExperiment(args.level, seq, '', [s], cBox, cSlice, (not args.noClearHL), True)
|
||||
nb = runCacheExperimentCode(ec.code, ec.init, prevOti + ec.oneTimeInit, loop=args.loop, warmUpCount=0, codeOffset=codeOffset,
|
||||
nMeasurements=args.nMeasurements, agg='med')
|
||||
yv.append(nb['L' + str(args.level) + '_HIT'])
|
||||
yv.sort()
|
||||
|
||||
ec = getCodeForCacheExperiment(args.level, seq, initSeq='', cacheSetList=[s], cBox=cBox, clearHL=True, wbinvd=True)
|
||||
oneTimeInit = prevEc.oneTimeInit + 'mov R15, ' + str(args.loop*args.nMeasurements) + '; pLoop:' + prevEc.code + '; dec R15; jnz pLoop; ' + ec.oneTimeInit
|
||||
yvStr = str(yv) if len(yv) <= 5 else '[%s, %s, ..., %s, %s]' % (yv[0], yv[1], yv[-2], yv[-1])
|
||||
log.info('CBox ' + str(cBox) + ', slice: ' + str(cSlice) + ', run ' + str(i) + ', set: ' + str(si+1) + '/' + str(len(prevSets)) +
|
||||
' (' + str(s) + '), ' + yvStr)
|
||||
|
||||
nb = runCacheExperimentCode(ec.code, ec.init, oneTimeInit, loop=args.loop, warmUpCount=0, codeOffset=codeOffset, nMeasurements=args.nMeasurements, agg='med')
|
||||
hits = nb['L' + str(args.level) + '_HIT']
|
||||
|
||||
yv = yValuesList[s]
|
||||
yv.append(hits)
|
||||
yv.sort()
|
||||
|
||||
yvStr = str(yv) if len(yv) <= 5 else '[%s, %s, ..., %s, %s]' % (yv[0], yv[1], yv[-2], yv[-1])
|
||||
log.info('CBox ' + str(cBox) + ', run ' + str(i) + ', set: ' + str(si+1) + '/' + str(len(prevSets)) + ' (' + str(s) + '), ' + yvStr)
|
||||
|
||||
if len(yv) >= 4 and yv[-1]-yv[0] > .5 and abs(yv[0]-yv[1]) < .5 and abs(yv[-1]-yv[-2]) < .5: #max(yValuesList[s]) - min(yValuesList[s]) > 0.1: #max(yValuesList[s]) > 2 and min(yValuesList[s]) < assoc/2:
|
||||
curSets.remove(s)
|
||||
notChanged = 0
|
||||
|
||||
if yv[-1]-yv[0] < .5:
|
||||
prevEc = ec
|
||||
if len(yv) > 1:
|
||||
if yv[-1]-yv[0] > 1:
|
||||
curSets.remove(s)
|
||||
notChanged = 0
|
||||
else:
|
||||
if useHitSeq:
|
||||
ec = getCodeForCacheExperiment(args.level, hitSeq, '', [s], cBox, cSlice, (not args.noClearHL), True)
|
||||
else:
|
||||
ec = getCodeForCacheExperiment(args.level, missSeq, '', [s], cBox, cSlice, (not args.noClearHL), True)
|
||||
prevOti = ec.oneTimeInit + 'mov R15, 100; pLoop:' + ec.code + '; dec R15; jnz pLoop; '
|
||||
|
||||
for cBox in range(0, nCBoxes):
|
||||
yValues = [min(x) + (max(x)-min(x))/2 for x in yValuesForCBox[cBox] if x]
|
||||
for cSlice in range(0, nSlicesPerCBox):
|
||||
fig = go.Figure()
|
||||
|
||||
fig = go.Figure()
|
||||
fig.update_layout(title_text='CBox ' + str(cBox) + ', Sequence (accessed ' + str(args.loop) + ' times in each set): ' + seq)
|
||||
fig.update_layout(showlegend=True)
|
||||
fig.update_xaxes(title_text='Set')
|
||||
fig.add_trace(go.Scatter(y=yValues, mode='lines+markers', name='L3 Hits'))
|
||||
title = 'CBox ' + str(cBox)
|
||||
if nSlicesPerCBox > 1: title += ', Slice: ' + str(cSlice)
|
||||
title += ', Sequence (accessed ' + str(args.loop) + ' times in each set): ' + seq
|
||||
fig.update_layout(title_text=title)
|
||||
|
||||
html.append(plot(fig, include_plotlyjs=False, output_type='div'))
|
||||
fig.update_layout(showlegend=True)
|
||||
fig.update_xaxes(title_text='Set')
|
||||
|
||||
yValuesMinMax = [min(x) + (max(x)-min(x))/2 for x in yValuesForSlice[cBox][cSlice] if x]
|
||||
fig.add_trace(go.Scatter(y=yValuesMinMax, mode='lines+markers', name='Min+(Max-Min)/2'))
|
||||
|
||||
yValuesMin = [min(x) for x in yValuesForSlice[cBox][cSlice] if x]
|
||||
fig.add_trace(go.Scatter(y=yValuesMin, mode='lines+markers', visible = 'legendonly', name='Min'))
|
||||
|
||||
yValuesMax = [max(x) for x in yValuesForSlice[cBox][cSlice] if x]
|
||||
fig.add_trace(go.Scatter(y=yValuesMax, mode='lines+markers', visible = 'legendonly', name='Max'))
|
||||
|
||||
html.append(plot(fig, include_plotlyjs=False, output_type='div'))
|
||||
|
||||
html += ['</body>', '</html>']
|
||||
|
||||
|
||||
Reference in New Issue
Block a user