[Chicago-talk] neat little optimization

Jim Thomason thomasoniii at gmail.com
Tue Oct 12 21:07:44 CDT 2004


In retrospect, this is a 'duh' optimization, but its uses are limited
enough that I guess it makes sense that I hadn't thought of it before.

One standard thing that I do fairly regularly is use objects as keys
into a hash.

sub expensive_calculation {
  my $self = shift;
  return $cached_calculations{$self} if defined $cached_calculations{$self};
  my $calculation = $self->_expensive_calculation;
  $cached_calculations{$self} = $calculation;
  return $calculation;
}

(yes, for the pedantic out there, that can be written tighter and
faster, but since the expensive calculation is only done once, I
greatly prefer expanding the syntax and having it be more legible)

Literally using the object as a key into a hash. So we can do our big
expensive calculations, then cache the value based upon the memory
address of the object. Subsequent hits only require the time for a
hash lookup, not to constantly re-do the expensive calculation. Joy!
Your program leaps in speed.

But, alas, that was not good enough for me. I'm currently optimizing
Basset and wringing as much speed as I possibly can out of it. I had
one method that was much slower than I felt it should be. Inspecting
it, it was fairly straightforward, and was using the object to lookup
in a hash a lot.

sub stack {
  my $self = shift;

  if (@_) {
   if ($_[0] == 0) {
    $cached{$self}  = 0;
   } else {
     $cached{$self} += shift;
   }

   $cached{$self} = 0 if $cached{$self} < 0;
  }

  return $cached{$self};
}

(simplified, of course)

But the point is, I was doing a lot of cache lookups using the
stringified object as the key. And then it hit me - I was using the
stringified object as the key. Why not cache it out?

sub stack {
  my $self = shift;

 my $key = '' . $self;

  if (@_) {
   if ($_[0] == 0) {
    $cached{$key}  = 0;
   } else {
     $cached{$key} += shift;
   }

   $cached{$key} = 0 if $cached{$key} < 0;
  }

  return $cached{$key};
}

Voila. The object is only stringified once, and the key is then used
for the lookup in the future. This little tidbit here yielded a 50%
speed increase (though, admittedly we're talking about going from
3,000/sec ->4,600 sec), which I was quite pleased with.

Uses? Minimal. You need a very frequently called function that does a
lot of hash lookups based upon the stringified version of the object.
If it doesn't do a lot of lookups or isn't called a hell of a lot, you
probably wouldn't even be able to measure the difference.

But for super speed critical stuff? Works like a charm.

-Jim...


More information about the Chicago-talk mailing list