[Zodb-checkins] CVS: ZODB3/ZEO - simul.py:1.9

Guido van Rossum guido@python.org
Mon, 9 Sep 2002 20:34:32 -0400


Update of /cvs-repository/ZODB3/ZEO
In directory cvs.zope.org:/tmp/cvs-serv24188

Modified Files:
	simul.py 
Log Message:
Add instrumentation to the simple free list allocator.


=== ZODB3/ZEO/simul.py 1.8 => 1.9 ===
--- ZODB3/ZEO/simul.py:1.8	Mon Sep  9 17:21:06 2002
+++ ZODB3/ZEO/simul.py	Mon Sep  9 20:34:32 2002
@@ -440,6 +440,10 @@
     def allocatorFactory(self, size):
         return SimpleAllocator(size)
 
+    def finish(self):
+        BuddyCacheSimulation.finish(self)
+        self.allocator.report()
+
 MINSIZE = 256
 
 class BuddyAllocator:
@@ -535,18 +539,41 @@
         self.rover = self.avail
         node = BlockNode(None, arenasize, 0)
         node.linkbefore(self.avail)
+        # Allocator statistics
+        self.nallocs = 0
+        self.nfrees = 0
+        self.allocloops = 0
+        self.freeloops = 0
+        self.freebytes = arenasize
+        self.freeblocks = 1
+        self.allocbytes = 0
+        self.allocblocks = 0
+
+    def report(self):
+        print ("NA=%d AL=%d NF=%d FL=%d ABy=%d ABl=%d FBy=%d FBl=%d" %
+               (self.nallocs, self.allocloops,
+                self.nfrees, self.freeloops,
+                self.allocbytes, self.allocblocks,
+                self.freebytes, self.freeblocks))
 
     def alloc(self, size):
-        # Exact fit algorithm
+        self.nallocs += 1
+        # First fit algorithm
         rover = stop = self.rover
         free = None
         while 1:
+            self.allocloops += 1
             if rover.size >= size:
                 if rover.size == size:
                     self.rover = rover.next
                     rover.unlink()
+                    self.freeblocks -= 1
+                    self.allocblocks += 1
+                    self.freebytes -= size
+                    self.allocbytes += size
                     return rover
                 free = rover
+                break
             rover = rover.next
             if rover is stop:
                 break
@@ -556,11 +583,20 @@
         assert free.size > size
         node = BlockNode(None, size, free.addr + free.size - size)
         free.size -= size
+        #self.freeblocks += 0 # No change here
+        self.allocblocks += 1
+        self.freebytes -= size
+        self.allocbytes += size
         return node
 
     def free(self, node):
+        self.nfrees += 1
+        self.freebytes += node.size
+        self.allocbytes -= node.size
+        self.allocblocks -= 1
         x = self.avail.next
         while x is not self.avail and x.addr < node.addr:
+            self.freeloops += 1
             x = x.next
         if node.addr + node.size == x.addr: # Merge with next
             x.addr -= node.size
@@ -568,16 +604,19 @@
             node = x
         else: # Insert new node into free list
             node.linkbefore(x)
+            self.freeblocks += 1
         x = node.prev
         if node.addr == x.addr + x.size and x is not self.avail:
             # Merge with previous node in free list
             node.unlink()
             x.size += node.size
             node = x
+            self.freeblocks -= 1
         # It's possible that either one of the merges above invalidated
         # the rover.
         # It's simplest to simply reset the rover to the newly freed block.
-        # XXX But is this optimal?
+        # It also seems optimal; if I only move the rover when it's
+        # become invalid, there performance goes way down.
         self.rover = node
 
     def dump(self, msg=""):
@@ -591,6 +630,7 @@
             count += 1
             node = node.next
         print count, "free blocks,", bytes, "free bytes"
+        self.report()
 
 class BlockNode(Node):