Skip to content.

plone.org

Sections
Personal tools
You are here: Home » Development » Plone Improvement Proposals » PLIP15
Log in
Development
You can submit bug reports and feature requests to the Plone Collector
We currently host development of Plone at SourceForge
There is also a Development Team area available for the Plone Developers. Site admins might find the Collective worth checking out. It contains many third-party add-on products.
Help regarding Plone development and deployment is available in the news groups and mailing lists.
 
Views

PLIP15

last edited 3 months ago by runyaga

SkinsTool?

One thing that seems to bog down Plone is the skinstool. try:

  • create ZPT in the root of your ZODB called, test_pt and it should only contain <html></html>
  • create a CMF site called cmf at the root of your ZODB
  • create a Plone site called plone at the root of your ZODB
  • now get ab out: http://mysite/test_pt, you will get ~150 req/second
  • now ab http://mysite/cmf/test_pt, you will get ~25 req/second
  • now ab http://mysite/plone/test_pt, you will get ~10 req/second

Why? To resolve a piece of content that is in the local folder or acquired outside a CMF/Plone object you need to search through the entire skinpaths; the more layers you have in your skinpath, the slower things get.

I have created some patches to Plone that speed up the way that the skin path gets searched by doing some strategic caching. Overall performance on my development box is improved by 30% in production mode and 100%(!) in debug mode. You can get the patched files from Plone CVS in the branch speedup_branch.

Psyco

I tried profiling Plone's index_html page using Dieter Maurer's excellent ZopeProfiler product to find the biggest consumers of cycles. Installing psyco and telling it to compile the worst offenders gives about a 10% speedup in production mode over and above the speedup from the patches above. Put the following in Plone's __init__.py:

    import psyco
    import TAL.TALInterpreter
    psyco.bind(TAL.TALInterpreter.TALInterpreter.interpret)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_startTag)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.attrAction_tal)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_rawtextBeginScope_tal)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.no_tag)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_condition)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.attrAction)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_optTag)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_setLocal_tal)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_rawtextColumn)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_endScope)
    psyco.bind(TAL.TALInterpreter.TALInterpreter.do_beginScope_tal)
    import AccessControl.ZopeGuards
    psyco.bind(AccessControl.ZopeGuards.guarded_getattr)
    import AccessControl.ZopeSecurityPolicy
    psyco.bind(AccessControl.ZopeSecurityPolicy.ZopeSecurityPolicy.validate)
    import AccessControl.SecurityManager
    psyco.bind(AccessControl.SecurityManager.SecurityManager.validate)
    import Products.PageTemplates.Expressions
    psyco.bind(Products.PageTemplates.Expressions.restrictedTraverse)
    psyco.bind(Products.PageTemplates.Expressions.PathExpr._eval)
    psyco.bind(Products.PageTemplates.Expressions.PathExpr.__call__)
    psyco.bind(Products.PageTemplates.Expressions.render)

The speedup_branch branch in Plone CVS also includes the psyco bindings together with some code for making it fail gracefully if psyco is not installed. (Note: the various security related bindings work fine on Zope 2.6.2 but fail on 2.7 - the speedup_branch also should manage the versions nicely as well)

Caching Macros/Views

ESI and SQUID

Removing redundant lookups

One trick that could make things crufty is binding the context namespace in a PythonScript? so if you traverse to a script the ZPT namespace will be bound to the scripts namespace parameter. For instance we could probably get rid of a lot of traversal this way. They key is to traverse the Python Script not call, here.scriptname(params) but here/scriptname. this means all calls that use python: are rules out. NOTE: It does not seem possible to mutate the namespace ;-( inside the ZPT.

I did some caching of global_defines by making a ExternalMethod? that looked up some of the non-dynamic parts og global_defines and cached it. When I ran my tests it went from about 80 req/second to 140 req/second. once you add the really dynamic expensive lookups i.e. listFilteredActionsFor and all the other variants. it goes down to around 30 req/second and 70 req/second. This is problematic as this (global_defines) limits the upperbounds that a dynamic page can render. A page can not go faster than that unless you are caching static views.

Idea:

  • split global_defines into 2 parts, static_defines and dynamic_defines. static_defines would cache all references to to images that are being used instead of traversing to them. For instance things like this suck, global_pathbar.pt: tal:define="addFavorite portal/addFavorite.gif" ? will fix that) Second: you are making a function call just to get Section508 compliant HTML. This could be calculated once for all requests.

    Idea: in the static_defines should have html pre-baked for all images. Use this instead of traversing to the object and then calling its tag. Why does that suck? because it may not be apparent where this is coming from. I would suggest having a dictionary that is generated once (or regenerated when invalidated) that has {'imageName':'raw html'} this could be in static defines and put into the zpt namespace. the above would get rid of the define and simply be . I would expect the static entries to no more than 100-200 items and we could allow a api for third party products to put their own constants. i believe dictionary lookup is very fast until we have ~200-300 items in a dictionary. maybe constants/plone/addFavorite.gif {'plone':{'addFavorite.gif':'html'}}

 

Powered by Plone

This site conforms to the following standards: