Tags:
create new tag
view all tags
I just performed a little experiment.

I've been bothered for quite some time about the way I implemented the singleton objects that TWiki uses. Based largely on what other people had done, I created a singleton TWiki object (the session) that was then used as a placeholder for all the other singletons required by TWiki (e.g. net, Store etc). I have been told subsequently, by the received wisdom on the web, that perl doesn't favour this approach. The common opinion is that pointer arithmetic is expensive in perl. So I thought it would be interesting to see what impact changing the singleton implementation would have.

First, the baseline. I benchmarked (using ab -n 5) two pages, the first being the default Main and the second a page with a smallish search on it. I ran ab 5 times each time, and took the fifth result. Default plugins only. MAIN (13172) delivers the following numbers.

mod_perl ab -n 5 WebHome ab -n 5 SearchPage
no 681.124 797.578
yes 356.568 566.048

I then modified the code to replace the "single singleton" TWiki session object with a global variable for each singleton. For example, $session->{net} is replaced with $TWiki::NET, $session->{form} with $TWiki::FORM etc. The session object itself is replaced with $TWiki::SESSION. The $session function parameter is eliminated throughout the codebase, and local is used to localise $TWiki::SESSION. The TWiki initialisation is written to take maximum advantage of object re-use, so most of the singleton objects are only generated if they don't already exist. This should ensure that when run with an accelerator, TWiki can re-use the Net, Form etc. singletons from a prior run.

mod_perl ab -n 5 WebHome ab -n 5 SearchPage
no 682.221 804.367
yes 621.540 1078.205

Because of the known problem with search under mod_perl, I re-ran it with NativeSearch enabled for comparison.

mod_perl ab -n 5 WebHome ab -n 5 SearchPage
no 681.171 797.605
yes 572.736 746.223

OK, that's interesting. It appears that using global variables is no faster (or any improvement is below the measurement threshold). Far more surprising, perhaps, is the result that when you use them with mod_perl, you lose a significant amount of the performance improvement you would normally expect!

I checked and rechecked these results. Maybe I'm snowblind now, so it would be a really good idea if someone was to review the patch and also run their own experiments. I have attached the patch here.

-- Contributors: CrawfordCurrie - 18 Mar 2007

Discussion

Wow, Crawford, what an experiment. I really appreciate your empirical approach to improvement considerations!

I'll try to go over the code, but without having looked, some thoughts which I am sure you have alredy considered...

  • Does the global variable approach leave a variable around somewhere which interferes with mod_perl?
  • Is global variable access under mod_perl slower than access to parameters?

One more comment that I have is that passing variables in parameters and taking offsets to get to fields, while involving adding and subtracting from addresses before accessing indirectly might not really qualify as pointer arithmetic. Without having studied the perl implementation I would guess that the address math would be done in the assembly code, not via pointer arithmetic in the ordinary sense. Could there be some confusion here about what constitutes pointer arithmetic?

-- ThomasWeigert - 21 Mar 2007

Ah, I used the term "pointer artihmetic" because I thought people would understand it. I imagine that the perl virtual machine is like the JVM, and has operations for this sort of thing, permitting preload optimisations and the like. I don't really know; the perl source is massive, complex, pretty opaque code.

The thing that surprised me most was that eliminating the session parameter didn't result in a speedup. I really thougt that, and the fact that local singletons don't have to be finish ed, would have a positive impact on the speed. I guess we have to look again at algorithm, rather than code.

-- CrawfordCurrie - 22 Mar 2007

I would not have expected global variables for the singletons to have a big effect on a "TWiki-measurable" scale. The only "expensive" pointers I know about are those to object methods, as compared to static function calls:

  • $object->method(@params) needs a runtime lookup for the class where $object is in, then a check whether method is defined in that class, and if it isn't, walk through the class's @ISA array.
  • Object::Class::method($object,@params) is often "the same thing", especially in TWiki core. You are sacrifying method inheritance which is not used with these singletons. With that usage, the target subroutine of the call is fixed at compile time.

Replacing $session->{object}->method() by $TWiki::OBJECT->method() just replaces the hash lookup in %$session by the hash lookup in TWiki's symbol table, but retains the "expensive" object method call.

I would guess that the effect of replacing a dozen or so of the hitlist subroutines which are called via their object (e.g. $this->_processTags(...) ) by static calls like TWiki::_processTags($this,...) will show an effect which is an order of magnitude greater. Which still might mean that it is neglegible on a TWiki scale....

Re mod_perl: I have no idea why the speedup is gone with global variables. One guess would be to check whether it leaks memory: global variables never go out of scope, so there might be chances for new circular references which are not caught by the current finish() methods.

I've been thinking about a "persistent" TWiki object in mod_perl context for some while, and I believe it has potential. Such an object would really deserve the variable name $session, while currently it actually is a per-request object. However, such persistence must be done really careful. Different server processes will each have their own object, and each process will only update its own copy.

-- HaraldJoerg - 22 Mar 2007

Thanks Harald. The idea of bypassing the inheritance mechanisms hadn't occurred to me, but it's obvious when you point it out. I must try that.

Do you have a list of "hitlist subroutines"? Every time I profile TWiki I get a different hitlist; even between different runs of the same code. I've reached the point where the only approach I can think of is to try and heal the "death of a thousand cuts" one cut at a time.

-- CrawfordCurrie - 24 Mar 2007

I have started the experiment yesterday, without convincing results so far. I am still fighting with setup details after migration to another virtual machine, so things make progress only slowly.

What I've done is to run BenchmarkContrib for Main.WebHome and check the routines which are most frequently called - those numbers do not vary. For this type of optimisation it is irrelevant how long the called routines will take, only the number of calls matters. I'll attach the result of one of the runs (Main.WebHome in SVN TWiki), for what it's worth.

At first I stumbled over TWiki::_processTags, called 322 times: The underscore convention suggests that it is a routine which is private to TWiki.pm (and apparently it is). It calls itself recursively via the object, so maybe one can a handcrafted topic for better measurement.

Some other hitlist routines:

Routine # of calls Remark
TWiki::normalizeWebTopicName 150 Needs the TWiki object to pass it to _expandTagOnTopicRendering for WEB variables. 150 times? This looks like a candidate for a variable cache.
TWiki::Prefs::getPreferencesValue 558 Not a candidate IMHO, should keep object syntax
TWiki::_expandTagOnTopicRendering 328  
TWiki::Render::takeOutBlocks 352 Doesn't even use the object
TWiki::Render::putBackBlocks 345 Doesn't even use the object
TWiki::Sandbox::untaintUnchecked 888 No object routine
TWiki::Store::_singleKey 683 No object routine
TWiki::Attrs::remove 614 Not called from within Attrs.pm

-- HaraldJoerg - 24 Mar 2007

Topic attachments
I Attachment History Action Size Date Who Comment
HTMLhtm Main_WebHome_17.htm r1 manage 91.5 K 2007-03-24 - 22:03 HaraldJoerg DProf profile for SVN TWiki rev.13219, Main.WebHome
Unknown file formatpatch performance.patch r1 manage 346.1 K 2007-03-18 - 08:21 UnknownUser cd to lib and patch -p0 < performance.patch
Edit | Attach | Watch | Print version | History: r6 < r5 < r4 < r3 < r2 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r6 - 2007-03-24 - HaraldJoerg
 
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2026 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.