bug#60807: [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
On Sun, Jan 15, 2023 at 12:27 AM Mike Frysinger wrote: > On 14 Jan 2023 21:27, Jacob Bachmeyer wrote: > > Mike Frysinger wrote: > > > --- a/lib/Automake/FileUtils.pm > > > +++ b/lib/Automake/FileUtils.pm > > > @@ -42,6 +42,11 @@ use Exporter; > > > use File::stat; > > > use IO::File; > > > > > > +# Perl's builtin stat does not provide sub-second resolution. Use > > > Time::HiRes > > > +# if it's available instead. Hopefully one day perl will update. > > > +# https://github.com/Perl/perl5/issues/17900 > > > +my $have_time_hires = eval { require Time::HiRes; }; > > > + > > > use Automake::Channels; > > > use Automake::ChannelDefs; > > > > > > @@ -115,10 +120,18 @@ sub mtime ($) > > >return 0 > > > if $file eq '-' || ! -f $file; > > > > > > - my $stat = stat ($file) > > > -or fatal "cannot stat $file: $!"; > > > - > > > - return $stat->mtime; > > > + if ($have_time_hires) > > > +{ > > > + my @stat = Time::HiRes::stat ($file) > > > + or fatal "cannot stat $file: $!"; > > > + return $stat[9]; > > > +} > > > + else > > > +{ > > > + my $stat = stat ($file) > > > + or fatal "cannot stat $file: $!"; > > > + return $stat->mtime; > > > +} > > > } > > > > If you change that variable to a constant, you can eliminate the runtime > > overhead entirely, since Perl optimizes if(1) and if(0) and folds > > constants at compile time. > > > > Something like: > > > > use constant HAVE_Time_HiRes => eval { require Time::HiRes; }; > > > > Then: > > > > if (HAVE_Time_HiRes) > >... > > > > If you do this, Perl will inline the block actually used and elide the > > branch at runtime. This is generally useful for any test that can only > > go one way in a specific run of the program. > > thanks, i'll integrate that idea. i'm by no means a perl programmer. Thanks, Mike. It looks like this has been resolved slightly differently by a recent change from Paul Eggert, so I'm closing this.
[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
On 14 Jan 2023 21:27, Jacob Bachmeyer wrote: > Mike Frysinger wrote: > > --- a/lib/Automake/FileUtils.pm > > +++ b/lib/Automake/FileUtils.pm > > @@ -42,6 +42,11 @@ use Exporter; > > use File::stat; > > use IO::File; > > > > +# Perl's builtin stat does not provide sub-second resolution. Use > > Time::HiRes > > +# if it's available instead. Hopefully one day perl will update. > > +# https://github.com/Perl/perl5/issues/17900 > > +my $have_time_hires = eval { require Time::HiRes; }; > > + > > use Automake::Channels; > > use Automake::ChannelDefs; > > > > @@ -115,10 +120,18 @@ sub mtime ($) > >return 0 > > if $file eq '-' || ! -f $file; > > > > - my $stat = stat ($file) > > -or fatal "cannot stat $file: $!"; > > - > > - return $stat->mtime; > > + if ($have_time_hires) > > +{ > > + my @stat = Time::HiRes::stat ($file) > > + or fatal "cannot stat $file: $!"; > > + return $stat[9]; > > +} > > + else > > +{ > > + my $stat = stat ($file) > > + or fatal "cannot stat $file: $!"; > > + return $stat->mtime; > > +} > > } > > If you change that variable to a constant, you can eliminate the runtime > overhead entirely, since Perl optimizes if(1) and if(0) and folds > constants at compile time. > > Something like: > > use constant HAVE_Time_HiRes => eval { require Time::HiRes; }; > > Then: > > if (HAVE_Time_HiRes) >... > > If you do this, Perl will inline the block actually used and elide the > branch at runtime. This is generally useful for any test that can only > go one way in a specific run of the program. thanks, i'll integrate that idea. i'm by no means a perl programmer. -mike signature.asc Description: PGP signature
[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
Mike Frysinger wrote: Perl's builtin stat function returns timestamps that have 1 second resolution. This can lead automake needlessly regenerating files because it compares timestamps as "older than or equal to" rather than only "older than". This is perfectly reasonable as we have no way of knowing what file is older if they have the same value which means we must be pessimistic & assume an upate is required. However, given modern systems that are quite fast and can easily generate many files in less than an second, we end up doing a lot of extra work. Until Perl gets around to figuring out how to support subsecond timestamp resolution, optionally import the Time::HiRes module and use its stat function instead. If it's available, great, if not, then we're no worse off than we are today. Performance-wise, at least by using the testsuite, there doesn't seem to be any measurable difference. * lib/Automake/FileUtils.pm: Use Time::HiRes to lookup mtimes on files if available. --- lib/Automake/FileUtils.pm | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/Automake/FileUtils.pm b/lib/Automake/FileUtils.pm index 848ff22d1761..78e0942e9f53 100644 --- a/lib/Automake/FileUtils.pm +++ b/lib/Automake/FileUtils.pm @@ -42,6 +42,11 @@ use Exporter; use File::stat; use IO::File; +# Perl's builtin stat does not provide sub-second resolution. Use Time::HiRes +# if it's available instead. Hopefully one day perl will update. +# https://github.com/Perl/perl5/issues/17900 +my $have_time_hires = eval { require Time::HiRes; }; + use Automake::Channels; use Automake::ChannelDefs; @@ -115,10 +120,18 @@ sub mtime ($) return 0 if $file eq '-' || ! -f $file; - my $stat = stat ($file) -or fatal "cannot stat $file: $!"; - - return $stat->mtime; + if ($have_time_hires) +{ + my @stat = Time::HiRes::stat ($file) + or fatal "cannot stat $file: $!"; + return $stat[9]; +} + else +{ + my $stat = stat ($file) + or fatal "cannot stat $file: $!"; + return $stat->mtime; +} } If you change that variable to a constant, you can eliminate the runtime overhead entirely, since Perl optimizes if(1) and if(0) and folds constants at compile time. Something like: use constant HAVE_Time_HiRes => eval { require Time::HiRes; }; Then: if (HAVE_Time_HiRes) ... If you do this, Perl will inline the block actually used and elide the branch at runtime. This is generally useful for any test that can only go one way in a specific run of the program. -- Jacob
[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
On 14 Jan 2023 14:52, Karl Berry wrote: > +my $have_time_hires = eval { require Time::HiRes; }; > > I don't object. Although if there's no speed up in practice, I wonder if > it's worth the extra code (simple-enough though it is). -k there's no speed up in the execution of a single process, but there is a speedup for users when using these tools back-to-back as they don't have to regen as often. this fix is necessary for the next patch to speed up the testsuite by using a smaller delay. although that makes me realize i need to make the next patch work when the system doesn't have Time::HiRes so users don't hit test failures. there was only one test that checks current behavior, so shouldn't be too bad. -mike signature.asc Description: PGP signature
[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
+my $have_time_hires = eval { require Time::HiRes; }; I don't object. Although if there's no speed up in practice, I wonder if it's worth the extra code (simple-enough though it is). -k
[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
Perl's builtin stat function returns timestamps that have 1 second resolution. This can lead automake needlessly regenerating files because it compares timestamps as "older than or equal to" rather than only "older than". This is perfectly reasonable as we have no way of knowing what file is older if they have the same value which means we must be pessimistic & assume an upate is required. However, given modern systems that are quite fast and can easily generate many files in less than an second, we end up doing a lot of extra work. Until Perl gets around to figuring out how to support subsecond timestamp resolution, optionally import the Time::HiRes module and use its stat function instead. If it's available, great, if not, then we're no worse off than we are today. Performance-wise, at least by using the testsuite, there doesn't seem to be any measurable difference. * lib/Automake/FileUtils.pm: Use Time::HiRes to lookup mtimes on files if available. --- lib/Automake/FileUtils.pm | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/Automake/FileUtils.pm b/lib/Automake/FileUtils.pm index 848ff22d1761..78e0942e9f53 100644 --- a/lib/Automake/FileUtils.pm +++ b/lib/Automake/FileUtils.pm @@ -42,6 +42,11 @@ use Exporter; use File::stat; use IO::File; +# Perl's builtin stat does not provide sub-second resolution. Use Time::HiRes +# if it's available instead. Hopefully one day perl will update. +# https://github.com/Perl/perl5/issues/17900 +my $have_time_hires = eval { require Time::HiRes; }; + use Automake::Channels; use Automake::ChannelDefs; @@ -115,10 +120,18 @@ sub mtime ($) return 0 if $file eq '-' || ! -f $file; - my $stat = stat ($file) -or fatal "cannot stat $file: $!"; - - return $stat->mtime; + if ($have_time_hires) +{ + my @stat = Time::HiRes::stat ($file) + or fatal "cannot stat $file: $!"; + return $stat[9]; +} + else +{ + my $stat = stat ($file) + or fatal "cannot stat $file: $!"; + return $stat->mtime; +} } -- 2.39.0