[Checkins] SVN: z3c.pt/trunk/ Refactored file system based cache a bit and added a simple benchmark for the cache. The initial load speed for a template goes down significantly with the cache. Compared to zope.pagetemplate we are only 3x slower, compared to 50x slower when cooking each template on process startup.

Hanno Schlichting plone at hannosch.info
Sun Aug 3 16:24:13 EDT 2008


Log message for revision 89316:
  Refactored file system based cache a bit and added a simple benchmark for the cache. The initial load speed for a template goes down significantly with the cache. Compared to zope.pagetemplate we are only 3x slower, compared to 50x slower when cooking each template on process startup.
  

Changed:
  U   z3c.pt/trunk/CHANGES.txt
  U   z3c.pt/trunk/benchmark/benchmark/tests.py
  U   z3c.pt/trunk/src/z3c/pt/filecache.py
  U   z3c.pt/trunk/src/z3c/pt/template.py

-=-
Modified: z3c.pt/trunk/CHANGES.txt
===================================================================
--- z3c.pt/trunk/CHANGES.txt	2008-08-03 20:07:08 UTC (rev 89315)
+++ z3c.pt/trunk/CHANGES.txt	2008-08-03 20:24:12 UTC (rev 89316)
@@ -4,6 +4,11 @@
 Version 0.8.x
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+- Refactored file system based cache a bit and added a simple benchmark for
+  the cache. The initial load speed for a template goes down significantly
+  with the cache. Compared to zope.pagetemplate we are only 3x slower,
+  compared to 50x slower when cooking each template on process startup.
+
 - Got rid entirely of the _escape function and inlined the actual code
   instead. We go up again to 12x for path and 19x for Python expressions :)
   [hannosch]

Modified: z3c.pt/trunk/benchmark/benchmark/tests.py
===================================================================
--- z3c.pt/trunk/benchmark/benchmark/tests.py	2008-08-03 20:07:08 UTC (rev 89315)
+++ z3c.pt/trunk/benchmark/benchmark/tests.py	2008-08-03 20:24:12 UTC (rev 89316)
@@ -111,8 +111,8 @@
         t_z3c = timing(self.helloworld_z3c)
         t_zope = timing(self.helloworld_zope)
 
-        print "z3c.pt:            %.2f" % t_z3c
-        print "zope.pagetemplate: %.2f" % t_zope
+        print "z3c.pt:            %.3f" % t_z3c
+        print "zope.pagetemplate: %.3f" % t_zope
         print "                   %.2fX" % (t_zope/t_z3c)
 
     @benchmark(u"Big table (python)")
@@ -151,19 +151,43 @@
 
 class FileBenchmarkTestCase(BaseTestCase):
 
+    def setUp(self):
+        BaseTestCase.setUp(self)
+        self.files = os.path.abspath(os.path.join(__file__, '..', 'input'))
+
+    def _testfile(self, name):
+        return os.path.join(self.files, name)
+
+    @benchmark(u"Compilation (Cached)")
+    def testCache(self):
+        table = self.table
+
+        z3cfile = z3c.pt.PageTemplateFile(
+            self._testfile('bigtable_python_z3c.pt'))
+
+        zopefile = zope.pagetemplate.pagetemplatefile.PageTemplateFile(
+            self._testfile('bigtable_python_zope.pt'))
+
+        t_cached_z3c = timing(z3cfile.registry.load, z3cfile)
+        t_cook_z3c = timing(z3cfile.cook, ['table'])
+
+        t_zope = timing(zopefile._cook)
+
+        print "z3c.pt cooking:    %.3f" % t_cook_z3c
+        print ""
+        print "z3c.pt cached:     %.3f" % t_cached_z3c
+        print "zope.pagetemplate: %.3f" % t_zope
+        print "                   %.2fX" % (t_zope/t_cached_z3c)
+
     @benchmark(u"Big table (python) File")
     def testBigTablePythonFile(self):
         table = self.table
 
-        files = os.path.abspath(os.path.join(__file__, '..', 'input'))
-        def testfile(name):
-            return os.path.join(files, name)
-
         z3cfile = z3c.pt.PageTemplateFile(
-            testfile('bigtable_python_z3c.pt'))
+            self._testfile('bigtable_python_z3c.pt'))
 
         zopefile = zope.pagetemplate.pagetemplatefile.PageTemplateFile(
-            testfile('bigtable_python_zope.pt'))
+            self._testfile('bigtable_python_zope.pt'))
 
         t_z3c = timing(z3cfile.render, table=table)
         t_zope = timing(zopefile, table=table)
@@ -176,15 +200,11 @@
     def testBigTablePathFile(self):
         table = self.table
 
-        files = os.path.abspath(os.path.join(__file__, '..', 'input'))
-        def testfile(name):
-            return os.path.join(files, name)
-
         z3cfile = z3c.pt.PageTemplateFile(
-            testfile('bigtable_path_z3c.pt'))
+            self._testfile('bigtable_path_z3c.pt'))
 
         zopefile = zope.pagetemplate.pagetemplatefile.PageTemplateFile(
-            testfile('bigtable_path_zope.pt'))
+            self._testfile('bigtable_path_zope.pt'))
 
         t_z3c = timing(z3cfile.render, table=table, request=object())
         t_zope = timing(zopefile, table=table, request=object())

Modified: z3c.pt/trunk/src/z3c/pt/filecache.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/filecache.py	2008-08-03 20:07:08 UTC (rev 89315)
+++ z3c.pt/trunk/src/z3c/pt/filecache.py	2008-08-03 20:24:12 UTC (rev 89316)
@@ -41,30 +41,26 @@
 
 class CachingDict(UserDict):
 
-    def __init__(self, filename, mtime, pagetemplate):
+    def __init__(self, filename, mtime):
         UserDict.__init__(self)
+        signature = sha(filename).hexdigest()
+        self.cachedir = os.path.join(FILECACHE, signature)
+        self.mtime = mtime
 
-        if FILECACHE:
-            # Update ourselves with the values from the cache file
-            filename = sha(filename).hexdigest()
-            self.cachedir = os.path.join(FILECACHE, filename)
-            self.mtime = mtime
+    def load(self, pagetemplate):
+        if os.path.isdir(self.cachedir):
+            for cachefile in os.listdir(self.cachedir):
+                value = None
+                cachepath = os.path.join(self.cachedir, cachefile)
+                code = code_read(cachepath, self.mtime)
+                if code is not None:
+                    self[int(cachefile)] = pagetemplate.execute(code)
+                    pagetemplate._v_last_read = self.mtime
 
-            if os.path.isdir(self.cachedir):
-                for cachefile in os.listdir(self.cachedir):
-                    value = None
-                    cachepath = os.path.join(self.cachedir, cachefile)
-                    code = code_read(cachepath, self.mtime)
-                    if code is not None:
-                        self[int(cachefile)] = pagetemplate.execute(code)
-                        pagetemplate._v_last_read = mtime
+    def store(self, params, code):
+        key = hash(''.join(params))
+        if not os.path.isdir(self.cachedir):
+            os.mkdir(self.cachedir)
 
-    # If we don't have a file cache, behave like a normal instance level dict
-    if FILECACHE:
-        def store(self, params, code):
-            key = hash(''.join(params))
-            if not os.path.isdir(self.cachedir):
-                os.mkdir(self.cachedir)
-
-            cachefile = os.path.join(self.cachedir, str(key))
-            code_write(code, cachefile, self.mtime)
+        cachefile = os.path.join(self.cachedir, str(key))
+        code_write(code, cachefile, self.mtime)

Modified: z3c.pt/trunk/src/z3c/pt/template.py
===================================================================
--- z3c.pt/trunk/src/z3c/pt/template.py	2008-08-03 20:07:08 UTC (rev 89315)
+++ z3c.pt/trunk/src/z3c/pt/template.py	2008-08-03 20:24:12 UTC (rev 89316)
@@ -120,7 +120,11 @@
         # make sure file exists
         os.lstat(filename)
         self.filename = filename
-        self.registry = filecache.CachingDict(filename, self.mtime(), self)
+        if FILECACHE:
+            self.registry = filecache.CachingDict(filename, self.mtime())
+            self.registry.load(self)
+        else:
+            self.registry = {}
 
     def _get_filename(self):
         return getattr(self, '_filename', None)
@@ -141,7 +145,17 @@
             fs.write(self.source)
             fs.close()
 
+    def read(self):
+        fd = open(self.filename, 'r')
+        self.body = body = fd.read()
+        fd.close()
+        self.signature = hash(body)
+        self._v_last_read = self.mtime()
+
     def cook(self, params):
+        if self.body is None:
+            self.read()
+
         generator = self.translate(
             self.body, params=params, default_expression=self.default_expression)
         
@@ -171,11 +185,7 @@
 
     def render(self, **kwargs):
         if self._cook_check():
-            fd = open(self.filename, 'r')
-            self.body = body = fd.read()
-            fd.close()
-            self.signature = hash(body)
-            self._v_last_read = self.mtime()
+            self.read()
 
         signature = hash(''.join(kwargs))
         template = self.registry.get(signature, None)



More information about the Checkins mailing list