reimplement $^WIN32_SLOPPY_STAT as a magic var
authorDaniel Dragan <bulk88@hotmail.com>
Fri, 16 Oct 2015 21:49:20 +0000 (17:49 -0400)
committerTony Cook <tony@develop-help.com>
Mon, 19 Oct 2015 03:21:51 +0000 (14:21 +1100)
The original implementation in commit cba61fe146 was sloppy. It is named
like a special var, it is listed as a special var, but it was a regular GV.
Since nobody knows this var exists, and full stat is the default (which I
disagree with see below). There will be alot more PP and C/XS perl stat()
calls (atleast a couple to dozens or low 100s for short lived perl
processes) than reads/writes to this global scalar (rounded to 0 R/Ws)
in a Win32 perl process. So avoid the 1 usually failing GV package (hash)
lookup for each PP/XS/PL C stat by using magic vars and a C bool. This is
a perf increase. Use sv_true instead of SvTRUE_NN because this code is
extremely rare to execute and the macro has large machine code.

I disagree with the default being full stat with since this increases the
number of kernel IO calls and ASCII->UTF16 conversions, and there was
perf criticism in the original thread that implemented this
this http://www.nntp.perl.org/group/perl.perl5.porters/2006/02/msg109917.html
but why full stat is default is for another ticket. This patch lessens the
overhead of full stat until something else is decided.

Change the initial value of the sloppystat setting for miniperl to be true
instead of doing it in buildcustomize.pl in PP. Revert part of
commit 8ce7a7e8b0 "speed up miniperl require on Win32" to acomplish this.
Unlike Unix perl, no object files are shared between mini and full perl,
so changing the default is fine on Win32 Perl. If minitest/miniperl really
need hard link testing/support, they can explictly turn off sloppy stat
and enable full stat with the special var. Changing the stat default from
C for miniperl avoids creating the special GV on each miniperl process
start as it previously was with the buildcustomize.pl way.

Changing stat setting in C and not PP also saves a couple IO calls in
win32_stat when opening the first .pl if it isn't -e, and
opening buildcustomize.pl in all permutations. The PP code in S_parse_body
contains a -f. See ticket for this patch for details.

Only CPAN use of this special var is
File-Stat-Moose-0.06/lib/File/Stat/Moose.pm#L208  according to cpangrep.

gv.c
mg.c
pod/perldelta.pod
win32/win32.c
win32/win32.h
write_buildcustomize.pl

diff --git a/gv.c b/gv.c
index e82f18d..0283b2d 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -1975,6 +1975,10 @@ S_gv_magicalize(pTHX_ GV *gv, HV *stash, const char *name, STRLEN len,
            case '\027':        /* $^WARNING_BITS */
                if (strEQ(name2, "ARNING_BITS"))
                    goto magicalize;
+#ifdef WIN32
+               else if (strEQ(name2, "IN32_SLOPPY_STAT"))
+                   goto magicalize;
+#endif
                break;
            case '1':
            case '2':
diff --git a/mg.c b/mg.c
index ea39a67..0f1c314 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -1041,6 +1041,11 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
                          *PL_compiling.cop_warnings);
            }
        }
+#ifdef WIN32
+       else if (strEQ(remaining, "IN32_SLOPPY_STAT")) {
+           sv_setiv(sv, w32_sloppystat);
+       }
+#endif
        break;
     case '+':
        if (PL_curpm && (rx = PM_GETRE(PL_curpm))) {
@@ -2802,6 +2807,11 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
                }
            }
        }
+#ifdef WIN32
+       else if (strEQ(mg->mg_ptr+1, "IN32_SLOPPY_STAT")) {
+           w32_sloppystat = (bool)sv_true(sv);
+       }
+#endif
        break;
     case '.':
        if (PL_localizing) {
index 0138388..126ea55 100644 (file)
@@ -355,6 +355,19 @@ startup and changing the variable in the parent process or another process or
 editing <.bashrc> will not change the enviromental variable in other existing,
 running, processes.
 
+=item *
+
+One glob fetch was removed for each C<-X> or C<stat> call whether done from
+Perl code or internally from Perl's C code. The glob being looked up was
+C<${^WIN32_SLOPPY_STAT}> which is a special variable. This makes C<-X> and
+C<stat> slightly faster.
+
+=item *
+
+During Miniperl's process startup, during the build process, 4 to 8 IO calls
+related to the process starting C<.pl> and the C<buildcustomize.pl> file were
+removed from the code opening and executing the first 1 or 2 C<.pl> files.
+
 =back
 
 =back
index a3e1754..1f6bd91 100644 (file)
@@ -1463,10 +1463,6 @@ win32_stat(const char *path, Stat_t *sbuf)
     int         nlink = 1;
     BOOL        expect_dir = FALSE;
 
-    GV          *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
-                                         GV_NOTQUAL, SVt_PV);
-    BOOL        sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
-
     if (l > 1) {
        switch(path[l - 1]) {
        /* FindFirstFile() and stat() are buggy with a trailing
@@ -1507,7 +1503,7 @@ win32_stat(const char *path, Stat_t *sbuf)
     path = PerlDir_mapA(path);
     l = strlen(path);
 
-    if (!sloppy) {
+    if (!w32_sloppystat) {
         /* We must open & close the file once; otherwise file attribute changes  */
         /* might not yet have propagated to "other" hard links of the same file. */
         /* This also gives us an opportunity to determine the number of links.   */
@@ -4681,6 +4677,11 @@ Perl_sys_intern_init(pTHX)
     w32_timerid                 = 0;
     w32_message_hwnd            = CAST_HWND__(INVALID_HANDLE_VALUE);
     w32_poll_count              = 0;
+#ifdef PERL_IS_MINIPERL
+    w32_sloppystat              = TRUE;
+#else
+    w32_sloppystat              = FALSE;
+#endif
     for (i=0; i < SIG_SIZE; i++) {
        w32_sighandler[i] = SIG_DFL;
     }
@@ -4748,6 +4749,7 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
     dst->timerid                = 0;
     dst->message_hwnd          = CAST_HWND__(INVALID_HANDLE_VALUE);
     dst->poll_count             = 0;
+    dst->sloppystat             = src->sloppystat;
     Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
 }
 #  endif /* USE_ITHREADS */
index e997651..9b79e00 100644 (file)
@@ -504,6 +504,7 @@ struct interp_intern {
     UINT       timerid;
     unsigned   poll_count;
     Sighandler_t sigtable[SIG_SIZE];
+    bool sloppystat;
 };
 
 #define WIN32_POLL_INTERVAL 32768
@@ -537,6 +538,7 @@ struct interp_intern {
 #define w32_init_socktype      (PL_sys_intern.thr_intern.Winit_socktype)
 #define w32_use_showwindow     (PL_sys_intern.thr_intern.Wuse_showwindow)
 #define w32_showwindow (PL_sys_intern.thr_intern.Wshowwindow)
+#define w32_sloppystat (PL_sys_intern.sloppystat)
 
 #ifdef USE_ITHREADS
 void win32_wait_for_children(pTHX);
index 68e300f..cf56e33 100644 (file)
@@ -87,7 +87,6 @@ print $fh <<"EOT" or $error = "Can't print to $file: $!";
 # We are miniperl, building extensions
 # Replace the first entry of \@INC ("lib") with the list of
 # directories we need.
-${\($^O eq 'MSWin32' ? '${^WIN32_SLOPPY_STAT} = 1;':'')}
 splice(\@INC, 0, 1, $inc);
 \$^O = '$osname';
 __END__