No Longer "Premature" Optimization

Ovid on 2004-04-15T15:44:32

As expected, AI::Life::World is ridiculously slow. The C version of the program can run a million iterations in a few minutes. The Perl version takes a few days. There are many reasons for that and I've got a good handle on them, but it's going to be a long, tough slog to get this program performing at an acceptable level.

Amongst other things, this has reconfirmed my opinion that overloading accessors to also be mutators is a bad idea ($o->foo and $o->foo(7)). There's extra logic in the method and if I just separate the two (having a $o->set_foo), I get to avoid that. I also intend to get rid of Class::Struct and craft all of the methods by hand (or perhaps building methods at startup) to give me a bit more control over the performance of the system. I also need to figure out how to improve the speed at which the animals "see". The $agent->look method is taking about 25% of the entire run of the program.

The most radical idea I have, though, is to skip all data validation. I know this sounds terrible, but my thought is to use Devel::Profile to ensure that I am testing almost 100% of the program. From there, I'll start tracing the data flows and see if there's an entry point I can do data validation at and the just trust that it will work out internally. I've always admired tightrope walkers who don't use a net (I've also thought they were pretty stupid, too).


Class::Meta

Theory on 2004-04-15T17:21:47

You might want to check out my Class::Meta module. It does accessor and mutator generation at startup and data type validation. You can optionally turn off data type validation for production code, however, but provide your own simple code reference to generate accessors and mutators. I've been meaning to add this as a standard, but tuits are in short demand at the moment.

I also want to add "Semi Affordance" accessors, e.g., foo() and set_foo(). The current options are Perl-style accesors (foo()) and "Affordance" accessors (get_foo() and set_foo()).

Regards,

David

Re:Class::Meta

Ovid on 2004-04-15T17:56:34

That sounds interesting, but I have to confess that I want something as fast as this:

sub foo     { $_[0]->[FOO]         }
sub set_foo { $_[0]->[FOO] = $_[1] }

sub foo_list     { $_[0]->[FOO_LIST][$_[1]]         }
sub set_foo_list { $_[0]->[FOO_LIST][$_[1]] = $_[2] }

I confess that this makes me cringe, but again, this software is so incredibly slow that I'm looking at extrame measures.

Re:Class::Meta

Elian on 2004-04-15T18:07:39

Then dump objects. Perl's OO stuff is really slow in spots, and making method calls is one of 'em. Get out the big stick and break your abstraction, and I'd bet you'll find a factor of two or three speedup, possibly more.

Re:Class::Meta

Ovid on 2004-04-15T18:19:06

You're hurtin' me, man, you're hurtin' me! I've been painfully aware of this. Currently, nothing needs OO, but switching away from is daunting and will complicate further plans. I'm going to sleep poorly tonight, thanks to your suggestion :/

Re:Class::Meta

Theory on 2004-04-15T18:26:36

Well then perhaps you can fall back on direct hash access for your objects:

  my $foo = $obj->{foo};
  $obj->{foo} = $foo;

Yeah, I hate it too, but it's the fastest way to do it and still have "objects" of a sort.

--David

Re:Class::Meta

Ovid on 2004-04-15T18:28:52

Array lookups are typically faster than hash lookups. That's why I avoided the blessed hashes.

Re:Class::Meta

Elian on 2004-04-15T18:29:48

Hey, could be worse... at least I didn't recommend you port it to Parrot and run it with the JIT. (Granted, that's because then I'd feel responsible for the resulting speed of the program, but... :)

Re:Class::Meta

Ovid on 2004-04-15T18:43:59

Curiously, that's sort of an idea I considered a couple of days ago when I wrote "maybe it's time for me to start eyeing Parrot for some of this." One one hand, I'm doing this specifically in Perl so that any Perl programmer can pick it up and see how this stuff works. On the other hand, if a simulation "week" starts approaching real-time, ain't no one gonna wanna play. I suppose that Parrot would be an interesting compromise.

Re:Class::Meta

Elian on 2004-04-15T18:48:24

Nah, the interesting compromise is to whip up a simulation language and write the compiler, which targets parrot, in perl. There's alledgedly an article at O'Reilly's OnLamp.com site about this...

Re:Class::Meta

Ovid on 2004-04-15T19:03:09

chromatic was mentioning that yesterday at his Parrot/SDL talk. That's interesting. Hmmm ... maybe I don't need free time after all :)

Re:Class::Meta

chromatic on 2004-04-15T19:22:46

Patience; as soon as the copyeditor finishes with it in a couple of hours, I'll publish the link.

Re:Class::Meta

Elian on 2004-04-15T19:34:51

Copyediting? Sheesh, trying to give the world the mistaken impression that authors are, y'know, literate or something?

It's a conspiracy, I tell you! (or is that "its"? Hrm...)

Re:Class::Meta

Ovid on 2004-04-15T19:55:30

A writer and his editor were crawling through the desert, dying of thirst, when they discovers a small pond. Overjoyed, the writer starts drinking deeply when he notices the editor relieving himself in the water.

"What the heck do you think you're doing?" screamed the writer.

"Improving it."

(with sincerest apologies to chromatic :)

Re:Class::Meta

Ovid on 2004-04-15T20:01:31

... when they discovers ...

Sheesh. There's something supremely ironic about making a typo while making fun of editors.

Re:Class::Meta

jmm on 2004-04-15T18:43:33

I suspect that most of the time is involved in the computation of the next generation from the current one. That computation only requires the height of the display (m), the width of the display (n), and an (n x m) 2d-array of values to indicate whether the element is live. Extract these values out of the object, compute the new 2d-array of values, perhaps use the old 2d-array to determine which pints need updating on the display, and then replace it with the new one. Going through a 2d-array using object methods to access element multiple times would be extremely slow compared to indexed access. Other than this specific use, all other access to the data could use object methods without significant cost (and the compute-next-generation could be an internal method so it could have license to bypass accessor methods for its operation).

Re:Class::Meta

Theory on 2004-04-15T18:24:28

Yes, Class::Meta creates those accessors for you. Just use the Affordance Accessor builder and make all of your attributes of the type "scalar". I'll try to add a semi-affordance accessor builder to get rid of the set_ mutators in the next week.

David