?

Log in

No account? Create an account

Mon, Aug. 22nd, 2005, 01:10 pm
Cache in Hand

Oh God. The title puns are getting worse and worse.

I started playing around with caching strategies for Data::ICal::DateTime and ended up with these three strategies.

All of them assume this function

    sub get_name {                                                                       
        my $ics   = shift;
        my $span  = shift;
        my $start = ($span->start_is_open)? "infinite" : $span->start->epoch;
        my $end   = ($span->end_is_open)?   "infinite" : $span->end->epoch;
        return "$ics-$start-$end";
    }  

Memoize:

    tie my %cache => 'DB_File', $filename, O_RDWR|O_CREAT, 0666;                         
    memoize('events', NORMALIZER => 'get_name',                                          
                      SCALAR_CACHE => [HASH => \%cache]);                                
                                                                                     
    my @events = events($ics, $span);                                                    
                                                                                     
    sub events {                                                                         
        my $ics  = shift;                                                            
        my $span = shift;                                                            
        my $cal  = Data::ICal->new( filename => $ics );                              
        return $cal->events;                                                         
    }                                                                                    
                                                                                     

Pixie:

    my $pixie   = Pixie->new->connect('bdb:cache/cache.db');                               
    my $name   = get_name($ics, $set);                                                     
    my $events = $pixie->get_object_named($name);                                        
                                                                                         
    my @events;                                                                          
    if ($events) {                                                                       
        @events = @$events;                                                              
    } else {                                                                             
        my $cal = Data::ICal->new( filename => $ics);                                    
        @events = $cal->events($set);                                                    
        my $object = bless \@events, "Random";                                           
        $pixie->bind_name( $name => $object );                                           
    }        

Storable:

    my @events;
    my $name  = get_name($ics, $set);  
    my $cache = "cache/$name.cache";
    if (-e $cache) {                                                              
        # stat to check the cache is still valid...                                          
        @events = @{ Storable::retrieve( $cache ) };
    } else {
        my $cal = Data::ICal->new( filename => $ics );
        @events = $cal->events($span);
        Storable::store \@events, $cache;
    }

Benchmarked that gives -

 Benchmark: timing 1000 iterations of memoize, pixie, storable... 
   memoize:  4 wallclock secs ( 3.47 usr +  0.06 sys =  3.53 CPU) @ 283.29/s (n=1000)
     pixie: 13 wallclock secs (11.57 usr +  0.11 sys = 11.68 CPU) @ 85.62/s (n=1000) 
  storable:  4 wallclock secs ( 3.91 usr +  0.09 sys =  4.00 CPU) @ 250.00/s (n=1000)
               Rate    pixie storable  memoize
    pixie    85.6/s       --     -66%     -70% 
    storable  250/s     192%       --     -12%
    memoize   283/s     231%      13%       --  

Which is pretty respectable.

The full script I used to do this is here.