《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

275 lines
10 KiB

  1. #! /usr/bin/env python
  2. import sys
  3. from optparse import OptionParser
  4. import random
  5. import math
  6. def convert(size):
  7. length = len(size)
  8. lastchar = size[length-1]
  9. if (lastchar == 'k') or (lastchar == 'K'):
  10. m = 1024
  11. nsize = int(size[0:length-1]) * m
  12. elif (lastchar == 'm') or (lastchar == 'M'):
  13. m = 1024*1024
  14. nsize = int(size[0:length-1]) * m
  15. elif (lastchar == 'g') or (lastchar == 'G'):
  16. m = 1024*1024*1024
  17. nsize = int(size[0:length-1]) * m
  18. else:
  19. nsize = int(size)
  20. return nsize
  21. def hfunc(index):
  22. if index == -1:
  23. return 'MISS'
  24. else:
  25. return 'HIT '
  26. def vfunc(victim):
  27. if victim == -1:
  28. return '-'
  29. else:
  30. return str(victim)
  31. #
  32. # main program
  33. #
  34. parser = OptionParser()
  35. 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')
  36. parser.add_option('-f', '--addressfile', default='', help='a file with a bunch of addresses in it', action='store', type='string', dest='addressfile')
  37. 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')
  38. parser.add_option('-p', '--policy', default='FIFO', help='replacement policy: FIFO, LRU, OPT, UNOPT, RAND, CLOCK', action='store', type='string', dest='policy')
  39. parser.add_option('-b', '--clockbits', default=2, help='for CLOCK policy, how many clock bits to use', action='store', type='int', dest='clockbits')
  40. parser.add_option('-C', '--cachesize', default='3', help='size of the page cache, in pages', action='store', type='string', dest='cachesize')
  41. 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')
  42. parser.add_option('-s', '--seed', default='0', help='random number seed', action='store', type='string', dest='seed')
  43. parser.add_option('-N', '--notrace', default=False, help='do not print out a detailed trace', action='store_true', dest='notrace')
  44. parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
  45. (options, args) = parser.parse_args()
  46. print 'ARG addresses', options.addresses
  47. print 'ARG addressfile', options.addressfile
  48. print 'ARG numaddrs', options.numaddrs
  49. print 'ARG policy', options.policy
  50. print 'ARG clockbits', options.clockbits
  51. print 'ARG cachesize', options.cachesize
  52. print 'ARG maxpage', options.maxpage
  53. print 'ARG seed', options.seed
  54. print 'ARG notrace', options.notrace
  55. print ''
  56. addresses = str(options.addresses)
  57. addressFile = str(options.addressfile)
  58. numaddrs = int(options.numaddrs)
  59. cachesize = int(options.cachesize)
  60. seed = int(options.seed)
  61. maxpage = int(options.maxpage)
  62. policy = str(options.policy)
  63. notrace = options.notrace
  64. clockbits = int(options.clockbits)
  65. random.seed(seed)
  66. addrList = []
  67. if addressFile != '':
  68. fd = open(addressFile)
  69. for line in fd:
  70. addrList.append(int(line))
  71. fd.close()
  72. else:
  73. if addresses == '-1':
  74. # need to generate addresses
  75. for i in range(0,numaddrs):
  76. n = int(maxpage * random.random())
  77. addrList.append(n)
  78. else:
  79. addrList = addresses.split(',')
  80. if options.solve == False:
  81. print 'Assuming a replacement policy of %s, and a cache of size %d pages,' % (policy, cachesize)
  82. print 'figure out whether each of the following page references hit or miss'
  83. print 'in the page cache.\n'
  84. for n in addrList:
  85. print 'Access: %d Hit/Miss? State of Memory?' % int(n)
  86. print ''
  87. else:
  88. if notrace == False:
  89. print 'Solving...\n'
  90. # init memory structure
  91. count = 0
  92. memory = []
  93. hits = 0
  94. miss = 0
  95. if policy == 'FIFO':
  96. leftStr = 'FirstIn'
  97. riteStr = 'Lastin '
  98. elif policy == 'LRU':
  99. leftStr = 'LRU'
  100. riteStr = 'MRU'
  101. elif policy == 'MRU':
  102. leftStr = 'LRU'
  103. riteStr = 'MRU'
  104. elif policy == 'OPT' or policy == 'RAND' or policy == 'UNOPT' or policy == 'CLOCK':
  105. leftStr = 'Left '
  106. riteStr = 'Right'
  107. else:
  108. print 'Policy %s is not yet implemented' % policy
  109. exit(1)
  110. # track reference bits for clock
  111. ref = {}
  112. cdebug = False
  113. # need to generate addresses
  114. addrIndex = 0
  115. for nStr in addrList:
  116. # first, lookup
  117. n = int(nStr)
  118. try:
  119. idx = memory.index(n)
  120. hits = hits + 1
  121. if policy == 'LRU' or policy == 'MRU':
  122. update = memory.remove(n)
  123. memory.append(n) # puts it on MRU side
  124. except:
  125. idx = -1
  126. miss = miss + 1
  127. victim = -1
  128. if idx == -1:
  129. # miss, replace?
  130. # print 'BUG count, cachesize:', count, cachesize
  131. if count == cachesize:
  132. # must replace
  133. if policy == 'FIFO' or policy == 'LRU':
  134. victim = memory.pop(0)
  135. elif policy == 'MRU':
  136. victim = memory.pop(count-1)
  137. elif policy == 'RAND':
  138. victim = memory.pop(int(random.random() * count))
  139. elif policy == 'CLOCK':
  140. if cdebug:
  141. print 'REFERENCE TO PAGE', n
  142. print 'MEMORY ', memory
  143. print 'REF (b)', ref
  144. # hack: for now, do random
  145. # victim = memory.pop(int(random.random() * count))
  146. victim = -1
  147. while victim == -1:
  148. page = memory[int(random.random() * count)]
  149. if cdebug:
  150. print ' scan page:', page, ref[page]
  151. if ref[page] >= 1:
  152. ref[page] -= 1
  153. else:
  154. # this is our victim
  155. victim = page
  156. memory.remove(page)
  157. break
  158. # remove old page's ref count
  159. if page in memory:
  160. assert('BROKEN')
  161. del ref[victim]
  162. if cdebug:
  163. print 'VICTIM', page
  164. print 'LEN', len(memory)
  165. print 'MEM', memory
  166. print 'REF (a)', ref
  167. elif policy == 'OPT':
  168. maxReplace = -1
  169. replaceIdx = -1
  170. replacePage = -1
  171. # print 'OPT: access %d, memory %s' % (n, memory)
  172. # print 'OPT: replace from FUTURE (%s)' % addrList[addrIndex+1:]
  173. for pageIndex in range(0,count):
  174. page = memory[pageIndex]
  175. # now, have page 'page' at index 'pageIndex' in memory
  176. whenReferenced = len(addrList)
  177. # whenReferenced tells us when, in the future, this was referenced
  178. for futureIdx in range(addrIndex+1,len(addrList)):
  179. futurePage = int(addrList[futureIdx])
  180. if page == futurePage:
  181. whenReferenced = futureIdx
  182. break
  183. # print 'OPT: page %d is referenced at %d' % (page, whenReferenced)
  184. if whenReferenced >= maxReplace:
  185. # print 'OPT: ??? updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
  186. replaceIdx = pageIndex
  187. replacePage = page
  188. maxReplace = whenReferenced
  189. # print 'OPT: --> updating maxReplace (%d %d %d)' % (replaceIdx, replacePage, maxReplace)
  190. victim = memory.pop(replaceIdx)
  191. # print 'OPT: replacing page %d (idx:%d) because I saw it in future at %d' % (victim, replaceIdx, whenReferenced)
  192. elif policy == 'UNOPT':
  193. minReplace = len(addrList) + 1
  194. replaceIdx = -1
  195. replacePage = -1
  196. for pageIndex in range(0,count):
  197. page = memory[pageIndex]
  198. # now, have page 'page' at index 'pageIndex' in memory
  199. whenReferenced = len(addrList)
  200. # whenReferenced tells us when, in the future, this was referenced
  201. for futureIdx in range(addrIndex+1,len(addrList)):
  202. futurePage = int(addrList[futureIdx])
  203. if page == futurePage:
  204. whenReferenced = futureIdx
  205. break
  206. if whenReferenced < minReplace:
  207. replaceIdx = pageIndex
  208. replacePage = page
  209. minReplace = whenReferenced
  210. victim = memory.pop(replaceIdx)
  211. else:
  212. # miss, but no replacement needed (cache not full)
  213. victim = -1
  214. count = count + 1
  215. # now add to memory
  216. memory.append(n)
  217. if cdebug:
  218. print 'LEN (a)', len(memory)
  219. if victim != -1:
  220. assert(victim not in memory)
  221. # after miss processing, update reference bit
  222. if n not in ref:
  223. ref[n] = 1
  224. else:
  225. ref[n] += 1
  226. if ref[n] > clockbits:
  227. ref[n] = clockbits
  228. if cdebug:
  229. print 'REF (a)', ref
  230. if notrace == False:
  231. print 'Access: %d %s %s -> %12s <- %s Replaced:%s [Hits:%d Misses:%d]' % (n, hfunc(idx), leftStr, memory, riteStr, vfunc(victim), hits, miss)
  232. addrIndex = addrIndex + 1
  233. print ''
  234. print 'FINALSTATS hits %d misses %d hitrate %.2f' % (hits, miss, (100.0*float(hits))/(float(hits)+float(miss)))
  235. print ''