Procedural versus OO performance

Ovid on 2006-11-19T19:18:44

While playing around with ant algorithms to solve the traveling salesman problem, I realized that the procedural code I was using would probably be easier to read and maintain if I converted it to object oriented code. My ants turned into snails. Eventually I tried hand-tuned OO, my Class::BuildMethods, and Moose. Of course, ant algorithms are AI and and AI is computationally intensive, so while Perl makes it easy to code AI solutions, their runtime performance leaves much to be desired. The original C code was from AI Application Programming, 2nd Edition, by M. Tim Jones, and it runs much faster than the Perl version, of course.

Here are typical sample runs of the Perl code:

Procedural:
the code took:17 wallclock secs (15.73 usr +  0.07 sys = 15.80 CPU)

OO (blessed arrayref)
the code took:34 wallclock secs (32.65 usr +  0.13 sys = 32.78 CPU)

OO (blessed hashref):
the code took:35 wallclock secs (33.31 usr +  0.12 sys = 33.43 CPU)

BuildMethods:
the code took:44 wallclock secs (41.98 usr +  0.16 sys = 42.14 CPU)

Moose:
the code took:37 wallclock secs (35.26 usr +  0.16 sys = 35.42 CPU

Moose was not appreciably slower than traditional OO methods, though my Moose-fu is lacking. My Class::BuildMethods was the worst, but then, that's the price I pay for my "quick prototype" code.

It was interesting to note that the arrayref and the hashref didn't have an appreciable performance difference, but then, even inside of the classes, I was only reaching directly into the data structure in the getter/setters. Most of this overhead appears to be the method calls.

While do some fairly aggressive hand-tuning of the blessed arrayrefs, but still respecting encapsulation outside of the class, I managed to get the following benchmark:

the code took:29 wallclock secs (27.94 usr +  0.13 sys = 28.07 CPU)

That's still over 50% slower than the procedural version, but it does show that performance benefits can be gained when needed.


Class::Trait-using?

jjore on 2006-11-20T00:41:33

Is there a chance you could hit it with Class::Trait on the objects? That'd be running without a method cache.

Re:Class::Trait-using?

Ovid on 2006-11-20T07:18:54

I probably could at some point. Their's at least one part of the code which would lend itself to traits fairly well.

Moose::Role-ing?

Stevan on 2006-11-20T16:19:17

You could also try using Moose::Role as well, I would be interested to see how you thought the two (Class::Trait & Moose::Role) compared.

- Stevan

Re:Moose::Role-ing?

Ovid on 2006-11-20T16:32:50

I had already screwed up one part of the Moose code (setting a subtype on an accessor). I need to learn Moose better before moving on to advanced stuff.

I noticed in the Changelog that there are references to Moose performance improvements. It seemed to be fairly speedy for the stuff that I'm doing. Is it fast enough for general use?

Re:Moose::Role-ing?

Stevan on 2006-11-20T19:07:04

Is it fast enough for general use?

Maybe not quite yet. It is getting there though, the current set of performance enhancements are just simple things I found while doing the larger performance enhancements, which I hope to have ready by the end of the month.

- Stevan

Re:Moose::Role-ing?

Ovid on 2006-11-20T19:19:16

While we're on the subject of Moose, have you thought about adding Dump methods to Moose::Autobox? Using something like Data::Dump::Streamer to dump a code reference could be very handy for debugging.