#! /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 ''