Re: DateTime Performance

2003-08-04 Thread John Siracusa
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?

 DateTime-now(): 21 wallclock secs @ 547.95/s
(18.13 usr +  0.12 sys = 18.25 CPU)
 
 Ditto.

I'm assuming now() is slower than new() due to the system call overhead of
getting the current time...?

 Total Elapsed Time = 19.91729 Seconds
User+System Time = 14.60729 Seconds
 Exclusive Times
 %Time ExclSec CumulS #Calls sec/call Csec/c  Name
   27.6   4.035  4.685  20274   0.0002 0.0002  Params::Validate::_validate
   24.0   3.510 17.549  1   0.0004 0.0018  DateTime::new
   18.9   2.770  3.809  10001   0.0003 0.0004
 DateTime::Locale::_load_class_from_id
 
 This seems quite odd.  It really doesn't do much.
 
   8.96   1.309  2.647  10020   0.0001 0.0003  DateTime::TimeZone::BEGIN
 
 And this is completely mystifying.  Can you show us your code?

Sure, here it is:

for(1 .. 1)
{
  my $d = DateTime-new(year = 200, month = 1, day = 1, hour = 2, minute
= 3, second = 4);
}

Those stats were produced on a G3/400 running a development release of OS X
that uses some build of Perl 5.8.1, which could explain some oddness.  Here
is the same code run on a G4/800 using Perl 5.8.0 on the latest released
version of OS X 10.2:

Total Elapsed Time = 8.817281 Seconds
  User+System Time = 5.352659 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 60.4   3.236 10.844  1   0.0003 0.0011  DateTime::new
 44.7   2.395  3.305  10001   0.0002 0.0003
DateTime::Locale::_load_class_from_id
 43.3   2.318  2.127  20274   0.0001 0.0001  Params::Validate::_validate
 22.5   1.207  1.095  10001   0.0001 0.0001  DateTime::Locale::Base::new
 18.4   0.987  1.223  10020   0.0001 0.0001  DateTime::TimeZone::BEGIN
 17.5   0.939  0.465  5   0. 0.  DateTime::__ANON__
 15.2   0.818  0.645  10002   0.0001 0.0001
DateTime::_calc_local_components
 12.8   0.687  1.025  10002   0.0001 0.0001  DateTime::_calc_local_rd
 10.6   0.568  0.525  10002   0.0001 0.0001  DateTime::_calc_utc_rd
 8.20   0.439  0.225  10002   0. 0.  DateTime::_normalize_seconds
 7.83   0.419  0.275  1   0. 0.  DateTime::_last_day_of_month
 7.47   0.400  0.115  30006   0. 0.
DateTime::TimeZone::Floating::is_floating
 7.27   0.389  3.505  10001   0. 0.0004  DateTime::Locale::load
 5.79   0.310  0.214  10006   0. 0.
DateTime::TimeZone::Floating::BEGIN
 4.86   0.260  0.070  20004   0. 0.
DateTime::TimeZone::OffsetOnly::is_utc

Maybe that looks more sane to you?
 
 So, what does everyone else think of the object creation performance
 situation?  Is it simply good enough to be 3x faster that
 Date::Manip::ParseDate()?  Are there any obvious areas that I should
 consider before I start mucking around with DateTime::new()?
 
 Considering that up til now my concern has been primarily on getting
 things correct, I wouldn't worry about it.  There are definitely some big
 performance improvements possible.  One possibility is to move the leap
 second bits into the DateTime XS code, which should help a lot.  The
 timezone stuff can also benefit from being rewritten as XS, but that won't
 help the particular cases you benchmarked, since the UTC and floating time
 zones are quite fast already.

What about what I mentioned earlier: lazy (or lazier) evaluation in the
constructor?  Basically, I want construction with known values to be as fast
as possible since there's a chance I may not even look at the date fields of
my objects.  But it's a hassle to have special-case code that either doesn't
fetch or doesn't set the date fields of my objects, just so I can avoid the
relatively expansive calls to DateTime-new()

-John



Re: DateTime Performance

2003-08-04 Thread John Siracusa
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.
DateTime::_calc_local_components
 25.9   0.130  0.030  1   0. 0.  DateTime::__ANON__
 17.9   0.090  0.070   2001   0. 0.  DateTime::DefaultLocale
 15.9   0.080  0.040   4004   0. 0.
DateTime::TimeZone::OffsetOnly::is_utc
 15.9   0.080  0.030   2000   0. 0.  DateTime::_last_day_of_month
 15.9   0.080  0.040   2002   0. 0.  DateTime::_normalize_seconds
 13.9   0.070  0.010   6006   0. 0.
DateTime::TimeZone::Floating::is_floating
 13.9   0.070  0.069   2006   0. 0.
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



Re: DateTime Performance

2003-08-04 Thread John Siracusa
On 8/4/03 1:25 PM, Ben Bennett wrote:
 Why not make your module be lazy about whether or not it creates a
 DateTime?

I thought of that, but I also use the act of creating a DateTime object to
check the validity of date attributes.  Anyway, I think there's room for
DateTime-new() optimization even without adding lazy evaluation (see
earlier posts).

-John



Is anyone working on the Hebrew Calendar?

2003-08-04 Thread Steven J. Weinberger
Is anyone working on a DateTime::Calendar::Hebrew implemetation? I did the pre-requisite search with Google, but I couldn't find any mention 
of someone working on it.
I've been working with the Hebrew calendar for years, and I have loads of code (non object oriented), all based on Dershowitz-Reingold. I 
also have code that might be classified as DateTime::Calendar::Jewish or DateTime::Calendar::Hebrew::Religious, but we'll save that for 
later. Just need to get my head around the API requirements, and I should be able to put some code out there.

Steve