| 1 | #!/usr/bin/env python2
 | 
| 2 | """
 | 
| 3 | heap_growth.py
 | 
| 4 | """
 | 
| 5 | from __future__ import print_function
 | 
| 6 | 
 | 
| 7 | import sys
 | 
| 8 | 
 | 
| 9 | 
 | 
| 10 | class Space(object):
 | 
| 11 |   def __init__(self, space_size):
 | 
| 12 |     self.filled_size = 0
 | 
| 13 |     self.space_size = space_size
 | 
| 14 | 
 | 
| 15 | 
 | 
| 16 | def Simulate(spaces, alloc_sizes):
 | 
| 17 |   # TODO:
 | 
| 18 |   # - how to simulate garbage too
 | 
| 19 |   # - simulate semi-spaces
 | 
| 20 |   # - eventually we could TIGHTEN the heap?  Actually we might get that for
 | 
| 21 |   #   free?
 | 
| 22 | 
 | 
| 23 |   # Input:
 | 
| 24 |   # - Stream of Allocation Sizes
 | 
| 25 |   # Output:
 | 
| 26 |   # - Whether we should collect now
 | 
| 27 |   #   - this happens as rarely as possible, only when we have no space
 | 
| 28 |   # - Whether we should grow, and HOW MUCH (2x, 4x)
 | 
| 29 |   #   - this happens AFTER a collection, if we don't have much space left
 | 
| 30 |   #   - And we try to keep the sizes even
 | 
| 31 | 
 | 
| 32 |   space = spaces[0]
 | 
| 33 | 
 | 
| 34 |   for i, a in enumerate(alloc_sizes):
 | 
| 35 |     if space.filled_size + a > space.space_size:
 | 
| 36 |       do_collect = True
 | 
| 37 |     else:
 | 
| 38 |       do_collect = False
 | 
| 39 | 
 | 
| 40 |     # Assume we didn't collect anything
 | 
| 41 |     while float(space.filled_size) / space.space_size >= 0.8:
 | 
| 42 |       space.space_size *= 2
 | 
| 43 | 
 | 
| 44 |     space.filled_size += a
 | 
| 45 | 
 | 
| 46 |     yield a, space.filled_size, space.space_size, do_collect
 | 
| 47 | 
 | 
| 48 | 
 | 
| 49 | def main(argv):
 | 
| 50 |   initial_size = 256
 | 
| 51 |   spaces = [Space(initial_size), Space(initial_size)]
 | 
| 52 | 
 | 
| 53 |   fmt = '%10s %10s %10s %10s'
 | 
| 54 |   print(fmt % ('alloc', 'filled', 'space max', 'collect'))
 | 
| 55 | 
 | 
| 56 |   #alloc_sizes = range(50, 100)
 | 
| 57 |   alloc_sizes = range(0, 10000, 400)  # big allocations
 | 
| 58 |   for row in Simulate(spaces, alloc_sizes):
 | 
| 59 |     print(fmt % row)
 | 
| 60 | 
 | 
| 61 | 
 | 
| 62 | if __name__ == '__main__':
 | 
| 63 |   try:
 | 
| 64 |     main(sys.argv)
 | 
| 65 |   except RuntimeError as e:
 | 
| 66 |     print('FATAL: %s' % e, file=sys.stderr)
 | 
| 67 |     sys.exit(1)
 |