[bug#60807] [PATCH 1/2] mtime: use Time::HiRes::stat when available for subsecond resolution
Jacob Bachmeyer <[email protected]> Sat, 14 Jan 2023 21:27:35 -0600
| Newsgroups | gmane.comp.sysutils.automake.patches |
|---|---|
| Message-ID | <[email protected]> |
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