Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PATCH] PathTools, dont require() modules in subs likely to be in loops #14859

Closed
p5pRT opened this issue Aug 17, 2015 · 10 comments
Closed

[PATCH] PathTools, dont require() modules in subs likely to be in loops #14859

p5pRT opened this issue Aug 17, 2015 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 17, 2015

Migrated from rt.perl.org#125827 (status was 'resolved')

Searchable as RT125827$

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

From @bulk88

Created by @bulk88

See attached patch. write_buildcustomize went from ~70 calls to
pp_require to ~40 calls with this patch.

Perl Info

Flags:
         category=core
         severity=low

Site configuration information for perl 5.23.0:

Configured by Owner at Mon Jun 29 03:16:56 2015.

Summary of my perl5 (revision 5 version 23 subversion 0) configuration:
       Derived from: 63602a3fc27a417daf3c532b6a11ae6eba2a072a
       Platform:
         osname=MSWin32, osvers=5.1, archname=MSWin32-x86-multi-thread
         uname=''
         config_args='undef'
         hint=recommended, useposix=true, d_sigaction=undef
         useithreads=define, usemultiplicity=define
         use64bitint=undef, use64bitall=undef, uselongdouble=undef
         usemymalloc=n, bincompat5005=undef
       Compiler:
         cc='cl', ccflags ='-nologo -GF -W3 -O1 -MD -Zi -DNDEBUG -GL -DWIN32
-D_CONSOLE -DNO_STRICT  -DPERL_TEXTMODE_SCRIPTS -DPERL_IMPLICIT_CONTEXT
-DPERL_IMPLICIT_SYS -D_USE_32BIT_TIME_T',
         optimize='-O1 -MD -Zi -DNDEBUG -GL',
         cppflags='-DWIN32'
         ccversion='13.10.6030', gccversion='', gccosandvers=''
         intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234,
doublekind=3
         d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=8,
longdblkind=0
         ivtype='long', ivsize=4, nvtype='double', nvsize=8,
Off_t='__int64', lseeksize=8
         alignbytes=8, prototype=define
       Linker and Libraries:
         ld='link', ldflags ='-nologo -nodefaultlib -debug -opt:ref,icf
-ltcg 		-libpath:"c:\perl\lib\CORE" 		-machine:x86'
         libpth=\lib
         libs=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib
comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib
netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib
odbc32.lib odbccp32.lib comctl32.lib msvcrt.lib
         perllibs=oldnames.lib kernel32.lib user32.lib gdi32.lib
winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib
oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib
version.lib odbc32.lib odbccp32.lib comctl32.lib msvcrt.lib
         libc=msvcrt.lib, so=dll, useshrplib=true, libperl=perl523.lib
         gnulibc_version=''
       Dynamic Linking:
         dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
         cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug
-opt:ref,icf -ltcg 		-libpath:"c:\perl\lib\CORE" 		-machine:x86'

Locally applied patches:
         uncommitted-changes


@INC for perl 5.23.0:
         C:/perl521/srcnewb4opt/lib
         .


Environment for perl 5.23.0:
         HOME (unset)
         LANG (unset)
         LANGUAGE (unset)
         LD_LIBRARY_PATH (unset)
         LOGDIR (unset)
         PATH=C:\sperl\c\bin;C:\WINDOWS\system32;C:\Program Files\Microsoft
Visual Studio .NET 2003\Vc7\bin;C:\Program Files\Microsoft Visual Studio
.NET 2003\Common7\IDE;C:\WINDOWS;C:\Program Files\Git\cmd;C:\Program
Files\Microsoft Visual Studio .NET 2003\Common7\Tools\bin;C:\perl\bin
         PERL_BADLANG (unset)
         PERL_JSON_BACKEND=Cpanel::JSON::XS
         PERL_YAML_BACKEND=YAML
         SHELL (unset)








@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

From @bulk88

0001-PathTools-dont-require-modules-in-subs-likely-to-be-.patch
From 0ba767e9c1e8eb3911d5ff603b38ab8aa5d4ce4b Mon Sep 17 00:00:00 2001
From: Daniel Dragan <bulk88@hotmail.com>
Date: Mon, 17 Aug 2015 06:46:08 -0400
Subject: [PATCH] PathTools, dont require() modules in subs likely to be in
 loops

-since Cwd is always loaded in File:Spec:Unix at the top, require'ing it in
 a user's loop in _cwd is duplicative and wasteful
-since sub _cwd now has no real body anymore just alias it for
 speed(no callframe)/memory(no CV+ops)
-Cwd has PP parts if XS isn't available, on miniperl load full Cwd at the
 start instead below inside a sub
-File::Spec::Win32 doesn't need to load Cwd in a sub, probably in a user's
 loop, Cwd is loaded from File::Spec::Unix
-File::Spec loads an OS specific .pm, all the OS specific .pm'es load
 Unix.pm, hence all File::Spec::Functions needs to do is load File::Spec to
 get Unix.pm, not directly call for Unix.pm
---
 dist/PathTools/lib/File/Spec/Functions.pm |    1 -
 dist/PathTools/lib/File/Spec/Unix.pm      |   13 +++++--------
 dist/PathTools/lib/File/Spec/Win32.pm     |    1 -
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/dist/PathTools/lib/File/Spec/Functions.pm b/dist/PathTools/lib/File/Spec/Functions.pm
index 5c2cec0..e5927e4 100644
--- a/dist/PathTools/lib/File/Spec/Functions.pm
+++ b/dist/PathTools/lib/File/Spec/Functions.pm
@@ -37,7 +37,6 @@ require Exporter;
 
 %EXPORT_TAGS = ( ALL => [ @EXPORT_OK, @EXPORT ] );
 
-require File::Spec::Unix;
 my %udeps = (
     canonpath => [],
     catdir => [qw(canonpath)],
diff --git a/dist/PathTools/lib/File/Spec/Unix.pm b/dist/PathTools/lib/File/Spec/Unix.pm
index 48e2b60..523fad0 100644
--- a/dist/PathTools/lib/File/Spec/Unix.pm
+++ b/dist/PathTools/lib/File/Spec/Unix.pm
@@ -7,12 +7,13 @@ $VERSION = '3.57';
 my $xs_version = $VERSION;
 $VERSION =~ tr/_//;
 
-#dont try to load XSLoader and DynaLoader only to ultimately fail on miniperl
-if(!defined &canonpath && defined &DynaLoader::boot_DynaLoader) {
+
+if(!defined &canonpath) {
   eval {#eval is questionable since we are handling potential errors like
         #"Cwd object version 3.48 does not match bootstrap parameter 3.50
         #at lib/DynaLoader.pm line 216." by having this eval
-    if ( $] >= 5.006 ) {
+#dont try to load XSLoader and DynaLoader only to ultimately fail on miniperl
+    if ( $] >= 5.006 && defined &DynaLoader::boot_DynaLoader) {
 	require XSLoader;
 	XSLoader::load("Cwd", $xs_version);
     } else {
@@ -555,11 +556,7 @@ L<File::Spec>
 # Internal routine to File::Spec, no point in making this public since
 # it is the standard Cwd interface.  Most of the platform-specific
 # File::Spec subclasses use this.
-sub _cwd {
-    require Cwd;
-    Cwd::getcwd();
-}
-
+*_cwd = *Cwd::getcwd;
 
 # Internal method to reduce xx\..\yy -> yy
 sub _collapse {
diff --git a/dist/PathTools/lib/File/Spec/Win32.pm b/dist/PathTools/lib/File/Spec/Win32.pm
index 77e0fed..222a428 100644
--- a/dist/PathTools/lib/File/Spec/Win32.pm
+++ b/dist/PathTools/lib/File/Spec/Win32.pm
@@ -331,7 +331,6 @@ sub rel2abs {
     }
 
     if ( !defined( $base ) || $base eq '' ) {
-      require Cwd ;
       $base = Cwd::getdcwd( ($self->splitpath( $path ))[0] ) if defined &Cwd::getdcwd ;
       $base = $self->_cwd() unless defined $base ;
     }
-- 
1.7.9.msysgit.0

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

From @ap

* bulk88 <perlbug-followup@​perl.org> [2015-08-17 13​:30]​:

See attached patch. write_buildcustomize went from ~70 calls to
pp_require to ~40 calls with this patch.

I don’t like the reliance of modules on being loaded from specific other
modules that this introduces. Things should be self-contained as far as
possible.

You’ll get almost all of the same savings by turning every `require Cwd`
into a `use Cwd ()` at the top of the same file. That will “waste” what,
3 calls to pp_require total? But it saves future maintainers from having
to reason about the load order across files and possibly patching things
at long range to keep the conglomerate working.

Otherwise ++ (It’s not the ’90s any more.)

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Aug 17, 2015

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Aug 19, 2015

From @tonycoz

On Mon Aug 17 08​:24​:48 2015, aristotle wrote​:

I don’t like the reliance of modules on being loaded from specific other
modules that this introduces. Things should be self-contained as far as
possible.

You’ll get almost all of the same savings by turning every `require Cwd`
into a `use Cwd ()` at the top of the same file. That will “waste” what,
3 calls to pp_require total? But it saves future maintainers from having
to reason about the load order across files and possibly patching things
at long range to keep the conglomerate working.

I agree.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 19, 2015

From @bulk88

On Mon Aug 17 08​:24​:48 2015, aristotle wrote​:

* bulk88 <perlbug-followup@​perl.org> [2015-08-17 13​:30]​:

See attached patch. write_buildcustomize went from ~70 calls to
pp_require to ~40 calls with this patch.

I don’t like the reliance of modules on being loaded from specific other
modules that this introduces. Things should be self-contained as far as
possible.

File​::Spec is an abstract base class with almost no code in it, it is implemented with an OS specific class. All the OS specific classes happen to inherit from Unix class but that is upto the OS specific class to decide. File​::Spec​::Functions is a wrapper around File​::Spec class. The use/requires should match the class diagram. If an OS specific class wants to implement sub _cwd itself without Cwd.pm or Cwd.xs, it is free to do so. The _cwd sub isn't public API of File​::Spec.

You’ll get almost all of the same savings by turning every `require Cwd`
into a `use Cwd ()` at the top of the same file. That will “waste” what,
3 calls to pp_require total? But it saves future maintainers from having
to reason about the load order across files and possibly patching things
at long range to keep the conglomerate working.

The requires were moved to the top so they run once. File​::Spec's loading time is important since the short ExtUtils​::Command one liners use File​::Copy which loads File​::Spec. Each Perl_pp_require function takes 0.165 ms or .091 ms (removed timer overhead derived from Perl_pp_padsv which is very light) to execute for me. If you count 3500 perl process starts which load File​::Spec during make test (someone said it was ~7000 process starts to do a make test, I'll assume 1/3 are EU​::* processes and test.pl), .091*3500=318 ms saved. A make test is 25 to 30 minutes for me. Although 318 ms is 1/6000th of a make test, 300 ms is countable time. A couple hundred smoke tests later over some weeks, 300 ms turns into dozens of seconds. Adding "use Cwd" lines would take half a minute of scrolling and typing in the future. The CPU time saved exceeded human time.

Next question, who are the future maintainers you speak of, and why would they be removing Cwd.pm from PathTools distro and perl core which would requiring redesigning the class dependencies of PathTools/File​::Spec? What is flawed with File​::Spec's current package names? Is Cwd.pm going to be removed from PathTools in favor of Cwd​::Tiny.pm? How would CPAN code handle Cwd.pm being spun off into its own tarball?

If someone will redesign the class dependency of File​::Spec/Cwd for some unknown reason, changing use/require lines comes with the cost of touching the code to rename PathTool's .pm files and all of its classes. I feel your concerns about future changes are as valid as saying "This patch should only split function arguments between lines and not at logic operators since it will cause extra costs in the future when the code is ported to Python."

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Aug 20, 2015

From @ap

* bulk88 via RT <perlbug-followup@​perl.org> [2015-08-19 09​:25]​:

On Mon Aug 17 08​:24​:48 2015, aristotle wrote​:

* bulk88 <perlbug-followup@​perl.org> [2015-08-17 13​:30]​:

See attached patch. write_buildcustomize went from ~70 calls to
pp_require to ~40 calls with this patch.

I don’t like the reliance of modules on being loaded from specific
other modules that this introduces. Things should be self-contained
as far as possible.

File​::Spec is an abstract base class with almost no code in it, it is
implemented with an OS specific class. All the OS specific classes
happen to inherit from Unix class but that is upto the OS specific
class to decide. File​::Spec​::Functions is a wrapper around File​::Spec
class. The use/requires should match the class diagram. If an OS
specific class wants to implement sub _cwd itself without Cwd.pm or
Cwd.xs, it is free to do so. The _cwd sub isn't public API of
File​::Spec.

I wasn’t talking about either File​::Spec or File​::Spec​::Functions so
I’m not sure why you are?

(You didn’t even patch File​::Spec, so I cannot even have an objection to
your patch on that basis in the first place. Your File​::Spec​::Functions
change removes an active wart, I certainly won’t object to that.)

You’ll get almost all of the same savings by turning every `require
Cwd` into a `use Cwd ()` at the top of the same file. That will
“waste” what, 3 calls to pp_require total? But it saves future
maintainers from having to reason about the load order across files
and possibly patching things at long range to keep the conglomerate
working.

The requires were moved to the top so they run once.

Except in File​::Spec​::Win32 where instead of moving it to the top, you
removed it completely and made the file rely on File​::Spec​::Unix having
loaded Cwd for it. That is the entirety of my objection to the patch.

File​::Spec's loading time is important since the short
ExtUtils​::Command one liners use File​::Copy which loads File​::Spec.
Each Perl_pp_require function takes 0.165 ms or .091 ms (removed timer
overhead derived from Perl_pp_padsv which is very light) to execute
for me. If you count 3500 perl process starts which load File​::Spec
during make test (someone said it was ~7000 process starts to do
a make test, I'll assume 1/3 are EU​::* processes and test.pl),
.091*3500=318 ms saved. A make test is 25 to 30 minutes for me.
Although 318 ms is 1/6000th of a make test, 300 ms is countable time.
A couple hundred smoke tests later over some weeks, 300 ms turns into
dozens of seconds. Adding "use Cwd" lines would take half a minute of
scrolling and typing in the future. The CPU time saved exceeded human
time.

Dozens of seconds over the course of weeks. Well that convinced me. :-)

Next question, who are the future maintainers you speak of

It has had a few dozen patchers in the past​:
https://metacpan.org/changes/distribution/PathTools

Take your pick.

(I’m not sure how I’m supposed to interpret this question anyway​: après
nous le déluge or what, what sort of attitude is that?)

and why would they be removing Cwd.pm from PathTools distro and perl
core which would requiring redesigning the class dependencies of
PathTools/File​::Spec? What is flawed with File​::Spec's current package
names? Is Cwd.pm going to be removed from PathTools in favor of
Cwd​::Tiny.pm? How would CPAN code handle Cwd.pm being spun off into
its own tarball?

If someone will redesign the class dependency of File​::Spec/Cwd for
some unknown reason, changing use/require lines comes with the cost of
touching the code to rename PathTool's .pm files and all of its
classes.

I… have no idea what any of that has to do with anything I said.

I feel your concerns about future changes are as valid as saying "This
patch should only split function arguments between lines and not at
logic operators since it will cause extra costs in the future when the
code is ported to Python."

I have to qualify that, based on how much the content of your mail seems
to have had to do with the content of mine, the “you” that you refer to
here seems to be not me but someone entirely hallucinated.

And I will agree with you that that dude’s concerns are indeed about as
valid as you say.

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Nov 11, 2017

From zefram@fysh.org

The removal of "require File​::Spec​::Unix" from File​::Spec​::Functions is
faulty​: the code in that file makes specific reference to File​::Spec​::Unix
further down, as part of the XS optimisation. It is a breach of API
to assume that every File​::Spec subclass loads F​:S​:U. So I reject that
part of the patch.

The removal of "require Cwd" from F​:S​:Win32 is similarly faulty, since
the module needs Cwd to be loaded. It is not sufficient to assume that
F​:S​:U will load it; doing so is not an advertised feature of F​:S​:U.
However, I agree that the require shouldn't be inside ->rel2abs.
It should be done once, at file scope.

The proposed new version of _cwd in F​:S​:U is also breaking an API.
It gets called as a method, not a function, so will receive a useless
invocant argument that Cwd​::getcwd() is not documented to accept.
But since _cwd is not advertised as part of F​:S​:U's API, all uses of it
can change to just call Cwd​::getcwd() directly, as a function. It *is*
used by subclasses that inherit from F​:S​:U, and overridden by one,
but the override is unnecessary, and we can remove this method from the
tacit subclassing API.

The loading of Cwd from F​:S​:U can be simplified massively by relying on
Cwd's own non-XS fallback logic, rather than duplicating it. F​:S​:U can
just load the Cwd module in its entirety.

Rewritten version of the patch applied as commit
a337154.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Nov 16, 2017

From @xsawyerx

On 11/11/2017 11​:08 AM, Zefram wrote​:

The removal of "require File​::Spec​::Unix" from File​::Spec​::Functions is
faulty​: the code in that file makes specific reference to File​::Spec​::Unix
further down, as part of the XS optimisation. It is a breach of API
to assume that every File​::Spec subclass loads F​:S​:U. So I reject that
part of the patch.

The removal of "require Cwd" from F​:S​:Win32 is similarly faulty, since
the module needs Cwd to be loaded. It is not sufficient to assume that
F​:S​:U will load it; doing so is not an advertised feature of F​:S​:U.
However, I agree that the require shouldn't be inside ->rel2abs.
It should be done once, at file scope.

The proposed new version of _cwd in F​:S​:U is also breaking an API.
It gets called as a method, not a function, so will receive a useless
invocant argument that Cwd​::getcwd() is not documented to accept.
But since _cwd is not advertised as part of F​:S​:U's API, all uses of it
can change to just call Cwd​::getcwd() directly, as a function. It *is*
used by subclasses that inherit from F​:S​:U, and overridden by one,
but the override is unnecessary, and we can remove this method from the
tacit subclassing API.

The loading of Cwd from F​:S​:U can be simplified massively by relying on
Cwd's own non-XS fallback logic, rather than duplicating it. F​:S​:U can
just load the Cwd module in its entirety.

Rewritten version of the patch applied as commit
a337154.

I wish this email was part of the commit message as well.

Does anyone want to pick up cutting a new release of PathTools?
(Such release does not imply you take over the distribution, I assure
you. :)

@p5pRT p5pRT closed this as completed Nov 16, 2017
@p5pRT
Copy link
Author

p5pRT commented Nov 16, 2017

@xsawyerx - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant