build: let find answer the rebuild question

The -n caller of timestamp.pl only needs to know whether the stamp is the
newest file. The script reads the timestamp of every file to answer that,
which costs 0.09 s for the build directory of U-Boot with its 44000 files.
The rebuild check runs the script twice per package and per build.

Collect the paths first, and for -n ask find for the first file that is
newer than the stamp. find stops at that file, so the walk ends early when
there is work to do. The other modes keep the old code, and so does -n with
-follow, because find and the script treat a symbolic link to a file
differently there.

The check over the U-Boot build directory now takes 0.02 s. The result is
the same for all 44 build directories of the OpenWrt One. The time of a full
no-op build does not change on a machine with 24 cores, where the package
step waits for the dependency chain rather than for the checks.

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin committed 2026-09-22 18:18:58 +02:00
1 parent ac4f1dd36c
commit b5c4b58764
1 file changed
+32 -8
+32 -8
View File
@@ -37,10 +37,22 @@ sub get_ts($$) {
return ($ts, $fn);
}
sub any_newer($$$) {
my ($stamp, $paths, $options) = @_;
my $list = join(" ", map { -d $_ ? "$_/" : $_ } @$paths);
open FIND, "find $list -type f -and -not -path \\*/.svn\\* -and -not -path \\*CVS\\* $options -newer $stamp -print -quit 2>/dev/null |";
my $hit = <FIND>;
close FIND;
return defined $hit;
}
(@ARGV > 0) or push @ARGV, ".";
my $ts = 0;
my $n = ".";
my %options;
my @paths;
while (@ARGV > 0) {
my $path = shift @ARGV;
if ($path =~ /^-x/) {
@@ -54,15 +66,27 @@ while (@ARGV > 0) {
} elsif ($path =~ /^-/) {
$options{$path} = 1;
} else {
my ($tmp, $fname) = get_ts($path, $options{"findopts"});
if ($tmp > $ts) {
if ($options{'-F'}) {
$n = $fname;
} else {
$n = $path;
}
$ts = $tmp;
push @paths, $path;
}
}
my $findopts = $options{"findopts"} || "";
if (defined $options{"-n"} && !$options{"-p"} && !$options{"-t"} &&
!$options{"-F"} && $findopts !~ /-follow/) {
exit 1 unless -f $options{"-n"};
exit(any_newer($options{"-n"}, \@paths, $findopts) ? 1 : 0);
}
for my $path (@paths) {
my ($tmp, $fname) = get_ts($path, $findopts);
if ($tmp > $ts) {
if ($options{'-F'}) {
$n = $fname;
} else {
$n = $path;
}
$ts = $tmp;
}
}