Geen omschrijving
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.

malloc.py 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #! /usr/bin/env python
  2. import random
  3. from optparse import OptionParser
  4. class malloc:
  5. def __init__(self, size, start, headerSize, policy, order, coalesce, align):
  6. # size of space
  7. self.size = size
  8. # info about pretend headers
  9. self.headerSize = headerSize
  10. # init free list
  11. self.freelist = []
  12. self.freelist.append((start, size))
  13. # keep track of ptr to size mappings
  14. self.sizemap = {}
  15. # policy
  16. self.policy = policy
  17. assert(self.policy in ['FIRST', 'BEST', 'WORST'])
  18. # list ordering
  19. self.returnPolicy = order
  20. assert(self.returnPolicy in ['ADDRSORT', 'SIZESORT+', 'SIZESORT-', 'INSERT-FRONT', 'INSERT-BACK'])
  21. # this does a ridiculous full-list coalesce, but that is ok
  22. self.coalesce = coalesce
  23. # alignment (-1 if no alignment)
  24. self.align = align
  25. assert(self.align == -1 or self.align > 0)
  26. def addToMap(self, addr, size):
  27. assert(addr not in self.sizemap)
  28. self.sizemap[addr] = size
  29. # print 'adding', addr, 'to map of size', size
  30. def malloc(self, size):
  31. if self.align != -1:
  32. left = size % self.align
  33. if left != 0:
  34. diff = self.align - left
  35. else:
  36. diff = 0
  37. # print 'aligning: adding %d to %d' % (diff, size)
  38. size += diff
  39. size += self.headerSize
  40. bestIdx = -1
  41. if self.policy == 'BEST':
  42. bestSize = self.size + 1
  43. elif self.policy == 'WORST' or self.policy == 'FIRST':
  44. bestSize = -1
  45. count = 0
  46. for i in range(len(self.freelist)):
  47. eaddr, esize = self.freelist[i][0], self.freelist[i][1]
  48. count += 1
  49. if esize >= size and ((self.policy == 'BEST' and esize < bestSize) or
  50. (self.policy == 'WORST' and esize > bestSize) or
  51. (self.policy == 'FIRST')):
  52. bestAddr = eaddr
  53. bestSize = esize
  54. bestIdx = i
  55. if self.policy == 'FIRST':
  56. break
  57. if bestIdx != -1:
  58. if bestSize > size:
  59. # print 'SPLIT', bestAddr, size
  60. self.freelist[bestIdx] = (bestAddr + size, bestSize - size)
  61. self.addToMap(bestAddr, size)
  62. elif bestSize == size:
  63. # print 'PERFECT MATCH (no split)', bestAddr, size
  64. self.freelist.pop(bestIdx)
  65. self.addToMap(bestAddr, size)
  66. else:
  67. abort('should never get here')
  68. return (bestAddr, count)
  69. # print '*** FAILED TO FIND A SPOT', size
  70. return (-1, count)
  71. def free(self, addr):
  72. # simple back on end of list, no coalesce
  73. if addr not in self.sizemap:
  74. return -1
  75. size = self.sizemap[addr]
  76. if self.returnPolicy == 'INSERT-BACK':
  77. self.freelist.append((addr, size))
  78. elif self.returnPolicy == 'INSERT-FRONT':
  79. self.freelist.insert(0, (addr, size))
  80. elif self.returnPolicy == 'ADDRSORT':
  81. self.freelist.append((addr, size))
  82. self.freelist = sorted(self.freelist, key=lambda e: e[0])
  83. elif self.returnPolicy == 'SIZESORT+':
  84. self.freelist.append((addr, size))
  85. self.freelist = sorted(self.freelist, key=lambda e: e[1], reverse=False)
  86. elif self.returnPolicy == 'SIZESORT-':
  87. self.freelist.append((addr, size))
  88. self.freelist = sorted(self.freelist, key=lambda e: e[1], reverse=True)
  89. # not meant to be an efficient or realistic coalescing...
  90. if self.coalesce == True:
  91. self.newlist = []
  92. self.curr = self.freelist[0]
  93. for i in range(1, len(self.freelist)):
  94. eaddr, esize = self.freelist[i]
  95. if eaddr == (self.curr[0] + self.curr[1]):
  96. self.curr = (self.curr[0], self.curr[1] + esize)
  97. else:
  98. self.newlist.append(self.curr)
  99. self.curr = eaddr, esize
  100. self.newlist.append(self.curr)
  101. self.freelist = self.newlist
  102. del self.sizemap[addr]
  103. return 0
  104. def dump(self):
  105. print 'Free List [ Size %d ]: ' % len(self.freelist),
  106. for e in self.freelist:
  107. print '[ addr:%d sz:%d ]' % (e[0], e[1]),
  108. print ''
  109. #
  110. # main program
  111. #
  112. parser = OptionParser()
  113. parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
  114. parser.add_option('-S', '--size', default=100, help='size of the heap', action='store', type='int', dest='heapSize')
  115. parser.add_option('-b', '--baseAddr', default=1000, help='base address of heap', action='store', type='int', dest='baseAddr')
  116. parser.add_option('-H', '--headerSize', default=0, help='size of the header', action='store', type='int', dest='headerSize')
  117. parser.add_option('-a', '--alignment', default=-1, help='align allocated units to size; -1->no align', action='store', type='int', dest='alignment')
  118. parser.add_option('-p', '--policy', default='BEST', help='list search (BEST, WORST, FIRST)', action='store', type='string', dest='policy')
  119. parser.add_option('-l', '--listOrder', default='ADDRSORT', help='list order (ADDRSORT, SIZESORT+, SIZESORT-, INSERT-FRONT, INSERT-BACK)', action='store', type='string', dest='order')
  120. parser.add_option('-C', '--coalesce', default=False, help='coalesce the free list?', action='store_true', dest='coalesce')
  121. parser.add_option('-n', '--numOps', default=10, help='number of random ops to generate', action='store', type='int', dest='opsNum')
  122. parser.add_option('-r', '--range', default=10, help='max alloc size', action='store', type='int', dest='opsRange')
  123. parser.add_option('-P', '--percentAlloc',default=50, help='percent of ops that are allocs', action='store', type='int', dest='opsPAlloc')
  124. parser.add_option('-A', '--allocList', default='', help='instead of random, list of ops (+10,-0,etc)', action='store', type='string', dest='opsList')
  125. parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
  126. (options, args) = parser.parse_args()
  127. m = malloc(int(options.heapSize), int(options.baseAddr), int(options.headerSize),
  128. options.policy, options.order, options.coalesce, options.alignment)
  129. print 'seed', options.seed
  130. print 'size', options.heapSize
  131. print 'baseAddr', options.baseAddr
  132. print 'headerSize', options.headerSize
  133. print 'alignment', options.alignment
  134. print 'policy', options.policy
  135. print 'listOrder', options.order
  136. print 'coalesce', options.coalesce
  137. print 'numOps', options.opsNum
  138. print 'range', options.opsRange
  139. print 'percentAlloc', options.opsPAlloc
  140. print 'allocList', options.opsList
  141. print 'compute', options.solve
  142. print ''
  143. percent = int(options.opsPAlloc) / 100.0
  144. random.seed(int(options.seed))
  145. p = {}
  146. L = []
  147. assert(percent > 0)
  148. if options.opsList == '':
  149. c = 0
  150. j = 0
  151. while j < int(options.opsNum):
  152. pr = False
  153. if random.random() < percent:
  154. size = int(random.random() * int(options.opsRange)) + 1
  155. ptr, cnt = m.malloc(size)
  156. if ptr != -1:
  157. p[c] = ptr
  158. L.append(c)
  159. print 'ptr[%d] = Alloc(%d)' % (c, size),
  160. if options.solve == True:
  161. print ' returned %d (searched %d elements)' % (ptr + options.headerSize, cnt)
  162. else:
  163. print ' returned ?'
  164. c += 1
  165. j += 1
  166. pr = True
  167. else:
  168. if len(p) > 0:
  169. # pick random one to delete
  170. d = int(random.random() * len(L))
  171. rc = m.free(p[L[d]])
  172. print 'Free(ptr[%d])' % L[d],
  173. if options.solve == True:
  174. print 'returned %d' % rc
  175. else:
  176. print 'returned ?'
  177. del p[L[d]]
  178. del L[d]
  179. # print 'DEBUG p', p
  180. # print 'DEBUG L', L
  181. pr = True
  182. j += 1
  183. if pr:
  184. if options.solve == True:
  185. m.dump()
  186. else:
  187. print 'List? '
  188. print ''
  189. else:
  190. c = 0
  191. for op in options.opsList.split(','):
  192. if op[0] == '+':
  193. # allocation!
  194. size = int(op.split('+')[1])
  195. ptr, cnt = m.malloc(size)
  196. if ptr != -1:
  197. p[c] = ptr
  198. print 'ptr[%d] = Alloc(%d)' % (c, size),
  199. if options.solve == True:
  200. print ' returned %d (searched %d elements)' % (ptr, cnt)
  201. else:
  202. print ' returned ?'
  203. c += 1
  204. elif op[0] == '-':
  205. # free
  206. index = int(op.split('-')[1])
  207. if index >= len(p):
  208. print 'Invalid Free: Skipping'
  209. continue
  210. print 'Free(ptr[%d])' % index,
  211. rc = m.free(p[index])
  212. if options.solve == True:
  213. print 'returned %d' % rc
  214. else:
  215. print 'returned ?'
  216. else:
  217. abort('badly specified operand: must be +Size or -Index')
  218. if options.solve == True:
  219. m.dump()
  220. else:
  221. print 'List?'
  222. print ''