A proper no-op doesn't prove to be helpful for diagnosing this problem, at least not under File::Next, because if you no-op, file::next never does any traversal.
sub File::Spec::Unix::canonpath {
return "";
}
for i in $(seq 0 10 ); do time perl newer_depends_than.pl ; done 2>&1 | grep real
real 0m0.344s
real 0m0.340s
real 0m0.338s
real 0m0.337s
real 0m0.341s
real 0m0.341s
real 0m0.336s
real 0m0.341s
real 0m0.340s
real 0m0.341s
real 0m0.341s
Closest I can get to a usable no-op is:
sub File::Spec::Unix::canonpath {
return $_[1];
}
for i in $(seq 0 10 ); do time perl newer_depends_than.pl ; done 2>&1 | grep real
real 0m1.595s
real 0m1.593s
real 0m1.594s
real 0m1.600s
real 0m1.629s
real 0m1.592s
real 0m1.644s
real 0m1.603s
real 0m1.678s
real 0m1.620s
real 0m1.597s
And compare vs the stock ::canonpath
for i in $(seq 0 10 ); do time perl newer_depends_than.pl ; done 2>&1 | grep real
real 0m2.857s
real 0m2.812s
real 0m2.943s
real 0m2.825s
real 0m2.846s
real 0m2.836s
real 0m2.856s
real 0m2.832s
real 0m2.847s
real 0m2.817s
real 0m2.838s
That to me looks strongly like there is a significant amount of performance to be made.
For a comparison, I did a very basic replacement of canonpath with just the minimal amount of canonicalisation I thought would be needed,
sub File::Spec::Unix::canonpath {
return unless defined $_[1];
return q{/} if $_[1] eq q{/};
# marginally the fastest of
# $path =~ /\/\z// , substr( $path, -1, 1, '' ) and $path = substr( $path , .... )
# but this is likely to be perl specific
return substr( $_[1], 0, -1 ) if substr( $_[1], -1, 1 ) eq q{/} ;
return $_[1];
}
for i in $(seq 0 10 ); do time perl newer_depends_than.pl ; done 2>&1 | grep 'real'
real 0m2.401s
real 0m2.384s
real 0m2.507s
real 0m2.472s
real 0m2.388s
real 0m2.369s
real 0m2.378s
real 0m2.392s
real 0m2.389s
real 0m2.379s
real 0m2.398s
So thats roughly an improvement of 14% over the current implementation, but still 50% slower than a "no-op".