On 8/4/03 10:10 AM, John Siracusa wrote:
> On 8/4/03 12:26 AM, Dave Rolsky wrote:
>>> # "..." includes args: year, month, day, hour, minute, second
>>> DateTime->new(...): 16 wallclock secs @ 687.29/s
>>>    (14.48 usr +  0.07 sys = 14.55 CPU)
>> 
>> This does a lot of work, including calculating both UTC & local times,
>> which involves calculating leap seconds, etc.
> 
> Does it need to do that?  I mean, sure, eventually it might have to do that
> if I want to do some sort of date manipulation, or even just fetch or print
> the date.  But does it have to really do anything at all during object
> construction other than stash the args somewhere?

I played around with DateTime::new() and found that the biggest culprit is
this line:

    $self->{locale} = DateTime::Locale->load( $p{locale} );

The removal of which more than doubles the performance of calling
DateTime::new(...) with ymdhms args.  The only way to get a comparable
speedup is to remove every line below that one except for these two:

    bless $self, $class;
    return $self;

And even that only gives a ~90% speedup vs. the 100%+ gained by ditching
DateTime::Locale->load().  (Obviously all of this will hose DateTime's
actual functionality, but bear with me :)

Profiling showed that DateTime::Locale::_load_class_from_id() was being
called N+1 times during N calls to DateTime->new(...), and that it was #3 in
the dprofpp list (2000 iterations shown):

%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 47.8   0.663  2.135   2000   0.0003 0.0011  DateTime::new
 35.2   0.488  0.399   4274   0.0001 0.0001  Params::Validate::_validate
 31.6   0.439  0.517   2001   0.0002 0.0003
DateTime::Locale::_load_class_from_id
 15.8   0.219  0.313   2020   0.0001 0.0002  DateTime::TimeZone::BEGIN

I found that _load_class_from_id() unconditionally executes this code:

    eval "require $real_class";

Skipping that line was good for a 30%+ speed boost, but that got me
thinking...aren't the Locale objects loaded/created by _load_class_from_id()
singletons?  Replacing calls to _load_class_from_id() within
DateTime::Locale::load() with some dumb caching like this:

    $Cache_By_Id{$id} ||= $class->_load_from_id($id)

Resulted in an easy 50% speed-up for DateTime->new(...), and
_load_class_from_id() dropped completely off the dprofpp output:

Total Elapsed Time = 0.841889 Seconds
  User+System Time = 0.501889 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 116.   0.584  1.290   2000   0.0003 0.0006  DateTime::new
 79.3   0.398  0.287   4274   0.0001 0.0001  Params::Validate::_validate
 41.6   0.209  0.220   2002   0.0001 0.0001  DateTime::_calc_local_rd
 37.6   0.189  0.238   2020   0.0001 0.0001  DateTime::TimeZone::BEGIN
 31.6   0.159  0.150   2002   0.0001 0.0001  DateTime::_calc_utc_rd
 27.8   0.140  0.070   2002   0.0001 0.0000
DateTime::_calc_local_components
 25.9   0.130  0.030  10000   0.0000 0.0000  DateTime::__ANON__
 17.9   0.090  0.070   2001   0.0000 0.0000  DateTime::DefaultLocale
 15.9   0.080  0.040   4004   0.0000 0.0000
DateTime::TimeZone::OffsetOnly::is_utc
 15.9   0.080  0.030   2000   0.0000 0.0000  DateTime::_last_day_of_month
 15.9   0.080  0.040   2002   0.0000 0.0000  DateTime::_normalize_seconds
 13.9   0.070  0.010   6006   0.0000 0.0000
DateTime::TimeZone::Floating::is_floating
 13.9   0.070  0.069   2006   0.0000 0.0000
DateTime::TimeZone::Floating::BEGIN
 11.3   0.057  0.115      1   0.0573 0.1145  DateTime::Locale::register
 7.97   0.040  0.154      6   0.0067 0.0257  DateTime::Locale::BEGIN

(An aside: why is DateTime::DefaultLocale on this list at all?)

To test my theory that this kind of dumb caching is valid, I ran all of
DateTime::Locale's tests, and then ran DateTime's tests while using the
modified DateTime::Locale.  Everything passed.

So, assuming I'm not missing a finer point here, I'm thinking that one easy
speed-up for DateTime object creation would be to make the various
DateTime::Locale::* classes into singletons (using whatever the "proper"
method is for this in the DT project) and avoid repeated string evals and
repeated calls to _load_class_from_id().

Going further, if calls to DateTime::Locale->load(...) could be "memoized"
safely, that'd be great too :)

-John

Reply via email to