#! /usr/bin/env python
|
|
|
|
import sys
|
|
from optparse import OptionParser
|
|
import random
|
|
import math
|
|
|
|
def convert(size):
|
|
length = len(size)
|
|
lastchar = size[length-1]
|
|
if (lastchar == 'k') or (lastchar == 'K'):
|
|
m = 1024
|
|
nsize = int(size[0:length-1]) * m
|
|
elif (lastchar == 'm') or (lastchar == 'M'):
|
|
m = 1024*1024
|
|
nsize = int(size[0:length-1]) * m
|
|
elif (lastchar == 'g') or (lastchar == 'G'):
|
|
m = 1024*1024*1024
|
|
nsize = int(size[0:length-1]) * m
|
|
else:
|
|
nsize = int(size)
|
|
return nsize
|
|
|
|
def hfunc(index):
|
|
if index == -1:
|
|
return 'MISS'
|
|
else:
|
|
return 'HIT '
|
|
|
|
def vfunc(victim):
|
|
if victim == -1:
|
|
return '-'
|
|
else:
|
|
return str(victim)
|
|
|
|
#
|
|
# main program
|
|
#
|
|
parser = OptionParser()
|
|
parser.add_option('-a', '--addresses', default='-1', help='a set of comma-separated pages to access; -1 means randomly generate', action='store', type='string', dest='addresses')
|
|
parser.add_option('-f', '--addressfile', default='', help='a file with a bunch of addresses in it', action='store', type='string', dest='addressfile')
|
|
parser.add_option('-n', '--numaddrs', default='10', help='if -a (--addresses) is -1, this is the number of addrs to generate', action='store', type='string', dest='numaddrs')
|
|
parser.add_option('-p', '--policy', default='FIFO', help='replacement policy: FIFO, LRU, OPT, UNOPT, RAND, CLOCK', action='store', type='string', dest='policy')
|
|
parser.add_option('-b', '--clockbits', default=2, help='for CLOCK policy, how many clock bits to use', action='store', type='int', dest='clockbits')
|
|
parser.add_option('-C', '--cachesize', default='3', help='size of the page cache, in pages', action='store', type='string', dest='cachesize')
|
|
parser.add_option('-m', '--maxpage', default='10', help='if randomly generating page accesses, this is the max page number', action='store', type='string', dest='maxpage')
|
|
parser.add_option('-s', '--seed', default='0', help='random number seed', action='store', type='string', dest='seed')
|
|
parser.add_option('-N', '--notrace', default=False, help='do not print out a detailed trace', action='store_true', dest='notrace')
|
|
parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
print 'ARG addresses', options.addresses
|
|
print 'ARG addressfile', options.addressfile
|
|
print 'ARG numaddrs', options.numaddrs
|
|
print 'ARG policy', options.policy
|
|
print 'ARG clockbits', options.clockbits
|
|
print 'ARG cachesize', options.cachesize
|
|
print 'ARG maxpage', options.maxpage
|
|
print 'ARG seed', options.seed
|
|
print 'ARG notrace', options.notrace
|
|
print ''
|
|
|
|
addresses = str(options.addresses)
|
|
addressFile = str(options.addressfile)
|
|
numaddrs = int(options.numaddrs)
|
|
cachesize = int(options.cachesize)
|
|
seed = int(options.seed)
|
|
maxpage = int(options.maxpage)
|
|
policy = str(options.policy)
|
|
notrace = options.notrace
|
|
clockbits = int(options.clockbits)
|
|
|
|
random.seed(seed)
|
|
|
|
addrList = []
|
|
if addressFile != '':
|
|
fd = open(addressFile)
|
|
for line in fd:
|
|
addrList.append(int(line))
|
|
fd.close()
|
|
else:
|
|
if addresses == '-1':
|
|
# need to generate addresses
|
|
for i in range(0,numaddrs):
|
|
n = int(maxpage * random.random())
|
|
addrList.append(n)
|
|
else:
|
|
addrList = addresses.split(',')
|
|
|
|
if options.solve == False:
|
|
print 'Assuming a replacement policy of %s, and a cache of size %d pages,' % (policy, cachesize)
|
|
print 'figure out whether each of the following page references hit or miss'
|
|
print 'in the page cache.\n'
|
|
|
|
for n in addrList:
|
|
print 'Access: %d Hit/Miss? State of Memory?' % int(n)
|
|
print ''
|
|
|
|
else:
|
|
if notrace == False:
|
|
print 'Solving...\n'
|
|
|
|
# init memory structure
|
|
count = 0
|
|
memory = []
|
|
hits = 0
|
|
miss = 0
|
|
|
|
if policy == 'FIFO':
|
|
leftStr = 'FirstIn'
|
|
riteStr = 'Lastin '
|
|
elif policy == 'LRU':
|
|
leftStr = 'LRU'
|
|
riteStr = 'MRU'
|
|
elif policy == 'MRU':
|
|
leftStr = 'LRU'
|
|
riteStr = 'MRU'
|
|
elif policy == 'OPT' or policy == 'RAND' or policy == 'UNOPT' or policy == 'CLOCK':
|
|
leftStr = 'Left '
|
|
riteStr = 'Right'
|
|
else:
|
|
print 'Policy %s is not yet implemented' % policy
|
|
exit(1)
|
|
|
|
# track reference bits for clock
|
|
ref = {}
|
|
|
|
cdebug = False
|
|
|
|
# need to generate addresses
|
|
addrIndex = 0
|
|
for nStr in addrList:
|
|
# first, lookup
|
|
n = int(nStr)
|
|
try:
|
|
idx = memory.index(n)
|
|
hits = hits + 1
|
|
if policy == 'LRU' or policy == 'MRU':
|
|
update = memory.remove(n)
|
|
memory.append(n) # puts it on MRU side
|
|
except:
|
|
idx = -1
|
|
miss = miss + 1
|
|
|
|
victim = -1
|
|
if idx == -1:
|
|
# miss, replace?
|
|
# print 'BUG count, cachesize:', count, cachesize
|
|
if count == cachesize:
|
|
# must replace
|
|
if policy == 'FIFO' or policy == 'LRU':
|
|
victim = memory.pop(0)
|
|
elif policy == 'MRU':
|
|
victim = memory.pop(count-1)
|
|
elif policy == 'RAND':
|
|
victim = memory.pop(int(random.random() * count))
|
|
elif policy == 'CLOCK':
|
|
if cdebug:
|
|
print 'REFERENCE TO PAGE', n
|
|
print 'MEMORY ', memory
|
|
print 'REF (b)', ref
|
|
|
|
# hack: for now, do random
|
|
# victim = memory.pop(int(random.random() * count))
|
|
victim = -1
|
|
while victim == -1:
|
|
page = memory[int(random.random() * count)]
|
|
if cdebug:
|
|
print ' scan page:', page, ref[page]
|
|
if ref[page] >= 1:
|
|
ref[page] -= 1
|
|
else:
|
|
# this is our victim
|
|
victim = page
|
|
memory.remove(page)
|
|
break
|
|
|
|
# remove old page's ref count
|
|
if page in memory:
|
|
assert('BROKEN')
|
|
del ref[victim]
|
|
if cdebug:
|
|
print 'VICTIM', page
|
|
print 'LEN', len(memory)
|
|
print 'MEM', memory
|
|
print 'REF (a)', ref
|
|
|
|
elif policy == 'OPT':
|
|
maxReplace = -1
|
|
replaceIdx = -1
|
|
replacePage = -1
|
|
# print 'OPT: access %d, memory %s' % (n, memory)
|
|
# print 'OPT: replace from FUTURE (%s)' % addrList[addrIndex+1:]
|
|
for pageIndex in range(0,count):
|
|
page = memory[pageIndex]
|
|
# now, have page 'page' at index 'pageIndex' in memory
|
|
whenReferenced = len(addrList)
|
|
# whenReferenced tells us when, in the future, this was referenced
|
|
for futureIdx in range(addrIndex+1,len(addrList)):
|
|
futurePage = int(addrList[futureIdx])
|
|
if page == futurePage:
|
|
whenReferenced = futureIdx
|
|
break
|
|
# print 'OPT: page %d is referenced at %d' % (page, whenReferenced)
|
|
if whenReferenced >= maxReplace:
|
|
# print 'OPT: ??? updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
|
|
replaceIdx = pageIndex
|
|
replacePage = page
|
|
maxReplace = whenReferenced
|
|
# print 'OPT: --> updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
|
|
victim = memory.pop(replaceIdx)
|
|
# print 'OPT: replacing page %d (idx:%d) because I saw it in future at %d' % (victim, replaceIdx, whenReferenced)
|
|
elif policy == 'UNOPT':
|
|
minReplace = len(addrList) + 1
|
|
replaceIdx = -1
|
|
replacePage = -1
|
|
for pageIndex in range(0,count):
|
|
page = memory[pageIndex]
|
|
# now, have page 'page' at index 'pageIndex' in memory
|
|
whenReferenced = len(addrList)
|
|
# whenReferenced tells us when, in the future, this was referenced
|
|
for futureIdx in range(addrIndex+1,len(addrList)):
|
|
futurePage = int(addrList[futureIdx])
|
|
if page == futurePage:
|
|
whenReferenced = futureIdx
|
|
break
|
|
if whenReferenced < minReplace:
|
|
replaceIdx = pageIndex
|
|
replacePage = page
|
|
minReplace = whenReferenced
|
|
victim = memory.pop(replaceIdx)
|
|
else:
|
|
# miss, but no replacement needed (cache not full)
|
|
victim = -1
|
|
count = count + 1
|
|
|
|
# now add to memory
|
|
memory.append(n)
|
|
if cdebug:
|
|
print 'LEN (a)', len(memory)
|
|
if victim != -1:
|
|
assert(victim not in memory)
|
|
|
|
# after miss processing, update reference bit
|
|
if n not in ref:
|
|
ref[n] = 1
|
|
else:
|
|
ref[n] += 1
|
|
if ref[n] > clockbits:
|
|
ref[n] = clockbits
|
|
|
|
if cdebug:
|
|
print 'REF (a)', ref
|
|
|
|
if notrace == False:
|
|
print 'Access: %d %s %s -> %12s <- %s Replaced:%s [Hits:%d Misses:%d]' % (n, hfunc(idx), leftStr, memory, riteStr, vfunc(victim), hits, miss)
|
|
addrIndex = addrIndex + 1
|
|
|
|
print ''
|
|
print 'FINALSTATS hits %d misses %d hitrate %.2f' % (hits, miss, (100.0*float(hits))/(float(hits)+float(miss)))
|
|
print ''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|