Reduce excessive stat calls in glob on VMS.
authorCraig A. Berry <craigberry@mac.com>
Sat, 22 Mar 2014 00:29:38 +0000 (19:29 -0500)
committerCraig A. Berry <craigberry@mac.com>
Sat, 22 Mar 2014 01:55:03 +0000 (20:55 -0500)
When PERL_EXTERNAL_GLOB is defined (currently only on VMS, or on other
platforms when running miniperl), each item returned from the glob
operation is checked against a set of glob metacharacters, and then, if
it matches any of these characters, it's checked with lstat() to see if
it actually exists.  Then it's passed through if it exists but skipped
otherwise.  Presumably this is because returning the pattern unchanged
is how a shell glob indicates "no match."

It appears that the lstat() is necessary because glob metacharacters
are almost always valid filename characters on Unix, so it's the
only way to distinguish a funny-looking but real filename from the no
match case (oops -- indeterminate grammar).  Since these filenames are
rare on Unix, lstat() is seldom called.

Enter VMS, where "external glob" is neither external, nor is it actually
a glob.  It is a native wildcard-matching search built into Perl with
vms/vms.c's Perl_vms_start_glob(), which does return the original
pattern when there is no match, but that pattern will only contain
native wildcard characters, so the check for glob metacharacters is
really not the right thing to be doing.  Moreover, glob metacharacters
such as dollar signs, brackets, and semicolons are extremely common in
native VMS paths, so in many common scenarios, the lstat() to see if the
file really exists gets triggered for every single file, which is
expensive.

This commit replaces, on VMS only, the check for glob metacharacters
with a check for VMS wildcard characters.  A simple glob of a Perl
source tree becomes 60% faster on the first iteration and 80% faster on
subsequent iterations.

Thanks to Hein van den Heuvel, who reported the problem and explained
that a search operation should only be looking at directory files,
whereas a stat does I/O to the individual file header, resulting in a
massive increase in unnecessary I/O.

This closes [perl #121440].

pp_hot.c

index c3637cd..ac69bc7 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1698,7 +1698,11 @@ Perl_do_readline(pTHX)
                }
            }
            for (t1 = SvPVX_const(sv); *t1; t1++)
+#ifdef __VMS
+               if (strchr("*%?", *t1))
+#else
                if (strchr("$&*(){}[]'\";\\|?<>~`", *t1))
+#endif
                        break;
            if (*t1 && PerlLIO_lstat(SvPVX_const(sv), &PL_statbuf) < 0) {
                (void)POPs;             /* Unmatched wildcard?  Chuck it... */