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

Regexp performance problem with swiped strings (?) #15643

Open
p5pRT opened this issue Oct 3, 2016 · 15 comments
Open

Regexp performance problem with swiped strings (?) #15643

p5pRT opened this issue Oct 3, 2016 · 15 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 3, 2016

Migrated from rt.perl.org#129802 (status was 'open')

Searchable as RT129802$

@p5pRT
Copy link
Author

p5pRT commented Oct 3, 2016

From @ntyni

As reported by Leszek Dubiel in <https://bugs.debian.org/839600>,
there seems to be a regexp performance problem for certain inputs.

Here's a test case​:

=======================================
#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
  "assign" => sub {my $i=0; $s =~ /./ while $i++ < 100 },
  "concat" => sub {my $i=0; $cat =~ /./ while $i++ < 100 },
  "sprintf" => sub {my $i=0; $spr =~ /./ while $i++ < 100 },
});

which results here in

  Rate concat assign sprintf
concat 2928/s -- -94% -94%
assign 47733/s 1530% -- -0%
sprintf 47733/s 1530% 0% --

showing pathological performance with the 'concat' variant.

It goes away if the length of the base string $s is varied even slightly,
and seems to reappear in 8-byte increments or decrements. Some of those,
like 2**16 - 3, also blow up the 'sprintf' performance.

It happens on Debian 5.20, 5.24, and also on current blead.
I've bisected that it regressed around 5.19.7 with

commit 9ffd39a
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Wed Nov 13 18​:10​:49 2013 -0800

  Allow PADTMPs’ strings to be swiped

Perl Info

Flags:
    category=core
    severity=medium

Site configuration information for perl 5.24.1:

Configured by Debian Project at Sun Sep 25 20:22:41 UTC 2016.

Summary of my perl5 (revision 5 version 24 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=3.16.0, archname=x86_64-linux-gnu-thread-multi
    uname='linux localhost 3.16.0 #1 smp debian 3.16.0 x86_64 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dcc=x86_64-linux-gnu-gcc -Dcpp=x86_64-linux-gnu-cpp -Dld=x86_64-linux-gnu-gcc -Dccflags=-DDEBIAN -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fdebug-prefix-map=/build/perl-H4FYPE/perl-5.24.1~rc3=. -fstack-protector-strong -Wformat -Werror=format-security -Dldflags= -Wl,-z,relro -Dlddlflags=-shared -Wl,-z,relro -Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.24 -Darchlib=/usr/lib/x86_64-linux-gnu/perl/5.24 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/x86_64-linux-gnu/perl5/5.24 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.24.1 -Dsitearch=/usr/local/lib/x86_64-linux-gnu/perl/5.24.1 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dusesitecustomize -Duse64bitint -Dman1ext=1 -Dman3ext=3perl
-Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -Ui_libutil -Uversiononly -DDEBUGGING=-g -Doptimize=-O2 -dEs -Duseshrplib -Dlibperl=libperl.so.5.24.1'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='x86_64-linux-gnu-gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include'
    ccversion='', gccversion='6.2.0 20160914', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='x86_64-linux-gnu-gcc', ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=libc-2.24.so, so=so, useshrplib=true, libperl=libperl.so.5.24
    gnulibc_version='2.24'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib -fstack-protector-strong'

Locally applied patches:
    RC3
    DEBPKG:debian/cpan_definstalldirs - Provide a sensible INSTALLDIRS default for modules installed from CPAN.
    DEBPKG:debian/db_file_ver - http://bugs.debian.org/340047 Remove overly restrictive DB_File version check.
    DEBPKG:debian/doc_info - Replace generic man(1) instructions with Debian-specific information.
    DEBPKG:debian/enc2xs_inc - http://bugs.debian.org/290336 Tweak enc2xs to follow symlinks and ignore missing @INC directories.
    DEBPKG:debian/errno_ver - http://bugs.debian.org/343351 Remove Errno version check due to upgrade problems with long-running processes.
    DEBPKG:debian/libperl_embed_doc - http://bugs.debian.org/186778 Note that libperl-dev package is required for embedded linking
    DEBPKG:fixes/respect_umask - Respect umask during installation
    DEBPKG:debian/writable_site_dirs - Set umask approproately for site install directories
    DEBPKG:debian/extutils_set_libperl_path - EU:MM: set location of libperl.a under /usr/lib
    DEBPKG:debian/no_packlist_perllocal - Don't install .packlist or perllocal.pod for perl or vendor
    DEBPKG:debian/fakeroot - Postpone LD_LIBRARY_PATH evaluation to the binary targets.
    DEBPKG:debian/instmodsh_doc - Debian policy doesn't install .packlist files for core or vendor.
    DEBPKG:debian/ld_run_path - Remove standard libs from LD_RUN_PATH as per Debian policy.
    DEBPKG:debian/libnet_config_path - Set location of libnet.cfg to /etc/perl/Net as /usr may not be writable.
    DEBPKG:debian/mod_paths - Tweak @INC ordering for Debian
    DEBPKG:debian/prune_libs - http://bugs.debian.org/128355 Prune the list of libraries wanted to what we actually need.
    DEBPKG:fixes/net_smtp_docs - [rt.cpan.org #36038] http://bugs.debian.org/100195 Document the Net::SMTP 'Port' option
    DEBPKG:debian/perlivp - http://bugs.debian.org/510895 Make perlivp skip include directories in /usr/local
    DEBPKG:debian/deprecate-with-apt - http://bugs.debian.org/747628 Point users to Debian packages of deprecated core modules
    DEBPKG:debian/squelch-locale-warnings - http://bugs.debian.org/508764 Squelch locale warnings in Debian package maintainer scripts
    DEBPKG:debian/skip-upstream-git-tests - Skip tests specific to the upstream Git repository
    DEBPKG:debian/patchlevel - http://bugs.debian.org/567489 List packaged patches for 5.24.1~rc3-3 in patchlevel.h
    DEBPKG:debian/skip-kfreebsd-crash - http://bugs.debian.org/628493 [perl #96272] Skip a crashing test case in t/op/threads.t on GNU/kFreeBSD
    DEBPKG:fixes/document_makemaker_ccflags - http://bugs.debian.org/628522 [rt.cpan.org #68613] Document that CCFLAGS should include $Config{ccflags}
    DEBPKG:debian/find_html2text - http://bugs.debian.org/640479 Configure CPAN::Distribution with correct name of html2text
    DEBPKG:debian/perl5db-x-terminal-emulator.patch - http://bugs.debian.org/668490 Invoke x-terminal-emulator rather than xterm in perl5db.pl
    DEBPKG:debian/cpan-missing-site-dirs - http://bugs.debian.org/688842 Fix CPAN::FirstTime defaults with nonexisting site dirs if a parent is writable
    DEBPKG:fixes/memoize_storable_nstore - [rt.cpan.org #77790] http://bugs.debian.org/587650 Memoize::Storable: respect 'nstore' option not respected
    DEBPKG:debian/regen-skip - Skip a regeneration check in unrelated git repositories
    DEBPKG:debian/makemaker-pasthru - http://bugs.debian.org/758471 Pass LD settings through to subdirectories
    DEBPKG:debian/makemaker-manext - http://bugs.debian.org/247370 Make EU::MakeMaker honour MANnEXT settings in generated manpage headers
    DEBPKG:debian/devel-ppport-reproducibility - http://bugs.debian.org/801523 Sort the list of XS code files when generating RealPPPort.xs
    DEBPKG:debian/encode-unicode-bom-doc - http://bugs.debian.org/798727 Document Debian backport of Encode::Unicode fix
    DEBPKG:debian/kfreebsd-softupdates - http://bugs.debian.org/796798 Work around Debian Bug#796798
    DEBPKG:fixes/autodie-scope - http://bugs.debian.org/798096 Fix a scoping issue with "no autodie" and the "system" sub
    DEBPKG:fixes/crosscompile-no-targethost - [23695c0] [perl #127234] Fix the Configure escape with usecrosscompile but no targethost
    DEBPKG:fixes/memoize-pod - [rt.cpan.org #89441] Fix POD errors in Memoize
    DEBPKG:fixes/ok-pod - Added encoding for pod.
    DEBPKG:debian/hurd-softupdates - http://bugs.debian.org/822735 Fix t/op/stat.t failures on hurd
    DEBPKG:fixes/nntp_docs - http://bugs.debian.org/51962 Net::NNTP: Correct innd/nnrpd confusion in relation to Reader option
    DEBPKG:fixes/math_complex_doc_great_circle - http://bugs.debian.org/697567 [rt.cpan.org #114104] Math::Trig: clarify definition of great_circle_midpoint
    DEBPKG:fixes/math_complex_doc_see_also - http://bugs.debian.org/697568 [rt.cpan.org #114105] Math::Trig: add missing SEE ALSO
    DEBPKG:fixes/math_complex_doc_angle_units - http://bugs.debian.org/731505 [rt.cpan.org #114106] Math::Trig: document angle units
    DEBPKG:fixes/cpan_web_link - http://bugs.debian.org/367291 CPAN: Add link to main CPAN web site
    DEBPKG:fixes/time_piece_doc - http://bugs.debian.org/817925 Time::Piece: Improve documentation for add_months and add_years
    DEBPKG:fixes/perlbug-refactor - http://bugs.debian.org/822463 [perl #128020] perlbug: Refactor duplicated file reading code
    DEBPKG:fixes/perlbug-linewrap - http://bugs.debian.org/822463 [perl #128020] perlbug: wrap overly long lines
    DEBPKG:fixes/hurd_sigaction - http://bugs.debian.org/825016 [d54f4ed] ext/POSIX/t/sigaction.t: Skip uid and pid tests on GNU/Hurd
    DEBPKG:fixes/hurd_hints - [4694301] http://bugs.debian.org/825020 [perl #128279] Modify hints for Hurd per Debian ticket 825020.
    DEBPKG:fixes/extutils-parsexs-reproducibility - [perl #128517] http://bugs.debian.org/829296 Make the output of ExtUtils::ParseXS reproducible
    DEBPKG:debian/CVE-2016-1238/sitecustomize-in-etc - Look for sitecustomize.pl in /etc/perl rather than sitelib on Debian systems
    DEBPKG:debian/CVE-2016-1238/test-suite-without-dot - [perl #127810] Patch unit tests to explicitly insert "." into @INC when needed.
    DEBPKG:debian/CVE-2016-1238/eumm-without-dot - [perl #127810] Add PERL_USE_UNSAFE_INC support to EU::MM for fortify_inc support.
    DEBPKG:debian/CVE-2016-1238/cpan-without-dot - [perl #127810] Set PERL_USE_UNSAFE_INC for cpan usage
    DEBPKG:debian/document_inc_removal - Document in perlvar that we remove '.' from @INC by default
    DEBPKG:fixes/extutils_makemaker_reproducible - http://bugs.debian.org/835815 http://bugs.debian.org/834190 Make perllocal.pod files reproducible
    DEBPKG:debian/CVE-2016-1238/remove-inc-test - Remove test for '.' in @INC as it might not be
    DEBPKG:debian/customized - Update customized.dat for files patched in Debian
    DEBPKG:fixes/file_path_hurd_errno - File-Path: Fix test failure in Hurd due to hard-coded ENOENT


@INC for perl 5.24.1:
    /etc/perl
    /usr/local/lib/x86_64-linux-gnu/perl/5.24.1
    /usr/local/share/perl/5.24.1
    /usr/lib/x86_64-linux-gnu/perl5/5.24
    /usr/share/perl5
    /usr/lib/x86_64-linux-gnu/perl/5.24
    /usr/share/perl/5.24
    /usr/local/lib/site_perl
    /usr/lib/x86_64-linux-gnu/perl-base


Environment for perl 5.24.1:
    HOME=/home/niko
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LC_CTYPE=fi_FI.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/niko/bin:/home/niko/bin:/home/niko/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin:/sbin:/usr/sbin
    PERL_BADLANG (unset)
    SHELL=/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Oct 4, 2016

From @iabyn

On Mon, Oct 03, 2016 at 01​:15​:27PM -0700, Niko Tyni wrote​:

# New Ticket Created by Niko Tyni
# Please include the string​: [perl #129802]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=129802 >

This is a bug report for perl from Niko Tyni <ntyni@​debian.org>,
generated with the help of perlbug 1.40 running under perl 5.24.1.

-----------------------------------------------------------------
[Please describe your issue here]

As reported by Leszek Dubiel in <https://bugs.debian.org/839600>,
there seems to be a regexp performance problem for certain inputs.

Here's a test case​:

=======================================
#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
"assign" => sub {my $i=0; $s =~ /./ while $i++ < 100 },
"concat" => sub {my $i=0; $cat =~ /./ while $i++ < 100 },
"sprintf" => sub {my $i=0; $spr =~ /./ while $i++ < 100 },
});

which results here in

   Rate  concat  assign sprintf

concat 2928/s -- -94% -94%
assign 47733/s 1530% -- -0%
sprintf 47733/s 1530% 0% --

showing pathological performance with the 'concat' variant.

It goes away if the length of the base string $s is varied even slightly,
and seems to reappear in 8-byte increments or decrements. Some of those,
like 2**16 - 3, also blow up the 'sprintf' performance.

It happens on Debian 5.20, 5.24, and also on current blead.
I've bisected that it regressed around 5.19.7 with

commit 9ffd39a
Author​: Father Chrysostomos <sprout@​cpan.org>
Date​: Wed Nov 13 18​:10​:49 2013 -0800

Allow PADTMPs’ strings to be swiped

This is down to a limitation in the COW implementation. Perl stores the
copy-on-write reference count in the spare byte (if any) just after the \0
at the end of the string. Depending on how the string has been allocated
and/or grown, it may not have a spare byte, and so the string has to be
copied after a match rather than COWed (the copy is so that $1, $2, $`, $&
etc remain with the correct values even if the string is subsequently
modified).

The PADTMP commit is not really relevant - it just happens to alter the
particular route by which a string ended up with SvCUR+1 == SvLEN.

You can see a similar slowdown on old perls (5.16.0 and earlier) if you
add $& somewhere in the test code - then all 3 cases run pathologically
slow.

The whole COW/SvGROW interaction is on my list of things to do.

--
"You may not work around any technical limitations in the software"
  -- Windows Vista license

@p5pRT
Copy link
Author

p5pRT commented Oct 4, 2016

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

@p5pRT
Copy link
Author

p5pRT commented Oct 4, 2016

From @ntyni

On Tue, Oct 04, 2016 at 09​:08​:02AM +0100, Dave Mitchell wrote​:

On Mon, Oct 03, 2016 at 01​:15​:27PM -0700, Niko Tyni wrote​:

# New Ticket Created by Niko Tyni
# Please include the string​: [perl #129802]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=129802 >

As reported by Leszek Dubiel in <https://bugs.debian.org/839600>,
there seems to be a regexp performance problem for certain inputs.

This is down to a limitation in the COW implementation. Perl stores the
copy-on-write reference count in the spare byte (if any) just after the \0
at the end of the string. Depending on how the string has been allocated
and/or grown, it may not have a spare byte, and so the string has to be
copied after a match rather than COWed (the copy is so that $1, $2, $`, $&
etc remain with the correct values even if the string is subsequently
modified).

The PADTMP commit is not really relevant - it just happens to alter the
particular route by which a string ended up with SvCUR+1 == SvLEN.

You can see a similar slowdown on old perls (5.16.0 and earlier) if you
add $& somewhere in the test code - then all 3 cases run pathologically
slow.

The whole COW/SvGROW interaction is on my list of things to do.

Many thanks for the explanation. Shouldn't the /n regexp modifier help
in that case? It doesn't seem to.
--
Niko Tyni ntyni@​debian.org

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @leszekdubiel

I have tested program below for $ARGV[0] in range of 0 to 2000 (two
twousand).

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5 - $ARGV[0]);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
  "assign" => sub { my $i=0; $s =~ /./ while $i++ < 100 },
  "concat" => sub { my $i=0; $cat =~ /./ while $i++ < 100 },
  "string" => sub { my $i=0; $spr =~ /./ while $i++ < 100 }
});
########### end

During this long run​:

  -- "concat" was extremely slow in 500 (five hundred) cases,
every fourth run -- $ARGV[0] = 0, 2, 4, 8, 12, 16, ...

  -- "assing" was extremely slow for $ARGV[0] = 6, 262, 518,
774, 1030, 1286, 1542, 1798, ...

  -- "string" was extremely slow for $ARGV[0] = 8, 264, 520,
776, 1032, 1288, 1544, 1800, ...

My function works on reference to big string, and here is ugly
workaround -- check if program is running extremely slow, and add one
space to string in that case (15 seconds)​:

sub ... {

while () {

  my $a = ... # big text

  # matching big text ...
  use v5.10;
  state $t = time;
  if (time > $t + 15) {
  my $x = pos $$a;
  $a .= " ";
  pos $a = $x;
  $t = time;
  }
  }
}

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @demerphq

On 29 October 2016 at 09​:46, Leszek Dubiel
<leszek.dubiel@​dubielvitrum.pl> wrote​:

I have tested program below for $ARGV[0] in range of 0 to 2000 (two
twousand).

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5 - $ARGV[0]);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
"assign" => sub { my $i=0; $s =~ /./ while $i++ < 100 },
"concat" => sub { my $i=0; $cat =~ /./ while $i++ < 100 },
"string" => sub { my $i=0; $spr =~ /./ while $i++ < 100 }
});
########### end

During this long run​:

   \-\- "concat" was extremely slow in 500 \(five hundred\) cases\, every

fourth run -- $ARGV[0] = 0, 2, 4, 8, 12, 16, ...

  \-\- "assing" was extremely slow for $ARGV\[0\] =  6\,  262\,  518\, 774\,

1030, 1286, 1542, 1798, ...

     \-\- "string" was extremely slow for $ARGV\[0\] = 8\,  264\, 520\,  776\,

1032, 1288, 1544, 1800, ...

My function works on reference to big string, and here is ugly workaround --
check if program is running extremely slow, and add one space to string in
that case (15 seconds)​:

sub ... {

while () {

my $a = \.\.\. \# big text

    \# matching big text \.\.\.
use v5\.10;
state $t = time;
if \(time > $t \+ 15\) \{
    my $x = pos $$a;
    $a \.= " ";
    pos $a = $x;
    $t = time;
\}

}
}

You have not told us your OS, or the version of Perl you are using,
and I cannot replicate this issue, so it is hard to say much.

Can you please provide the output of perl -V, and details about your os, etc.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @demerphq

On 30 October 2016 at 09​:51, demerphq <demerphq@​gmail.com> wrote​:

On 29 October 2016 at 09​:46, Leszek Dubiel
<leszek.dubiel@​dubielvitrum.pl> wrote​:

I have tested program below for $ARGV[0] in range of 0 to 2000 (two
twousand).

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5 - $ARGV[0]);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
"assign" => sub { my $i=0; $s =~ /./ while $i++ < 100 },
"concat" => sub { my $i=0; $cat =~ /./ while $i++ < 100 },
"string" => sub { my $i=0; $spr =~ /./ while $i++ < 100 }
});
########### end

During this long run​:

   \-\- "concat" was extremely slow in 500 \(five hundred\) cases\, every

fourth run -- $ARGV[0] = 0, 2, 4, 8, 12, 16, ...

  \-\- "assing" was extremely slow for $ARGV\[0\] =  6\,  262\,  518\, 774\,

1030, 1286, 1542, 1798, ...

     \-\- "string" was extremely slow for $ARGV\[0\] = 8\,  264\, 520\,  776\,

1032, 1288, 1544, 1800, ...

My function works on reference to big string, and here is ugly workaround --
check if program is running extremely slow, and add one space to string in
that case (15 seconds)​:

sub ... {

while () {

my $a = \.\.\. \# big text

    \# matching big text \.\.\.
use v5\.10;
state $t = time;
if \(time > $t \+ 15\) \{
    my $x = pos $$a;
    $a \.= " ";
    pos $a = $x;
    $t = time;
\}

}
}

You have not told us your OS, or the version of Perl you are using,
and I cannot replicate this issue, so it is hard to say much.

Can you please provide the output of perl -V, and details about your os, etc.

Actually, playing more, I can replicate in blead on linux (low numbers
are I think due to DEBUGGING build)

$ ./perl -Ilib t.pl 0
  Rate concat string assign
concat 3110/s -- -86% -86%
string 21920/s 605% -- -0%
assign 21976/s 607% 0% --

However perl 5.18.4 does not have this issue.

$ perl t.pl 0
  Rate assign concat string
assign 62877/s -- -0% -1%
concat 63015/s 0% -- -1%
string 63434/s 1% 1% --

My first guess is that this is an issue with COW and/or malloc.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @demerphq

On 30 October 2016 at 09​:57, demerphq <demerphq@​gmail.com> wrote​:

On 30 October 2016 at 09​:51, demerphq <demerphq@​gmail.com> wrote​:

On 29 October 2016 at 09​:46, Leszek Dubiel
<leszek.dubiel@​dubielvitrum.pl> wrote​:

I have tested program below for $ARGV[0] in range of 0 to 2000 (two
twousand).

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5 - $ARGV[0]);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
"assign" => sub { my $i=0; $s =~ /./ while $i++ < 100 },
"concat" => sub { my $i=0; $cat =~ /./ while $i++ < 100 },
"string" => sub { my $i=0; $spr =~ /./ while $i++ < 100 }
});
########### end

During this long run​:

   \-\- "concat" was extremely slow in 500 \(five hundred\) cases\, every

fourth run -- $ARGV[0] = 0, 2, 4, 8, 12, 16, ...

  \-\- "assing" was extremely slow for $ARGV\[0\] =  6\,  262\,  518\, 774\,

1030, 1286, 1542, 1798, ...

     \-\- "string" was extremely slow for $ARGV\[0\] = 8\,  264\, 520\,  776\,

1032, 1288, 1544, 1800, ...

My function works on reference to big string, and here is ugly workaround --
check if program is running extremely slow, and add one space to string in
that case (15 seconds)​:

sub ... {

while () {

my $a = \.\.\. \# big text

    \# matching big text \.\.\.
use v5\.10;
state $t = time;
if \(time > $t \+ 15\) \{
    my $x = pos $$a;
    $a \.= " ";
    pos $a = $x;
    $t = time;
\}

}
}

You have not told us your OS, or the version of Perl you are using,
and I cannot replicate this issue, so it is hard to say much.

Can you please provide the output of perl -V, and details about your os, etc.

Actually, playing more, I can replicate in blead on linux (low numbers
are I think due to DEBUGGING build)

$ ./perl -Ilib t.pl 0
Rate concat string assign
concat 3110/s -- -86% -86%
string 21920/s 605% -- -0%
assign 21976/s 607% 0% --

However perl 5.18.4 does not have this issue.

$ perl t.pl 0
Rate assign concat string
assign 62877/s -- -0% -1%
concat 63015/s 0% -- -1%
string 63434/s 1% 1% --

My first guess is that this is an issue with COW and/or malloc.

Well, it is COW, but indirectly.

Modifying your test code to show more detail​:

$ cat t.pl
#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';
print "Perl version $]\n";
use Devel​::Peek;

my $mod = $ARGV[0] || 0;

my $assign = "A"x (2**16 + 5 - $mod);
my $concat = 'B' . $assign . 'B';
my $string = sprintf "B%sB", $assign;

print STDERR "assign\n";
Dump($assign);
print STDERR "concat\n";
Dump($concat);
print STDERR "string\n";
Dump($string);

cmpthese(-1, {
  "assign" => sub { my $i=0; $assign =~ /./ while $i++ < 100 },
  "concat" => sub { my $i=0; $concat =~ /./ while $i++ < 100 },
  "string" => sub { my $i=0; $string =~ /./ while $i++ < 100 }
});

and then running it like this​:

./perl -Ilib t.pl 0 2>&1 | perl -pe's/A+/A+/g;'

We get this​:

$ ./perl -Ilib t.pl 0 2>&1 | perl -pe's/A+/A+/g;'
assign
SV = PV(0xfa8c38) at 0x10575d8
  REFCNT = 1
  FLA+GS = (POK,pPOK)
  PV = 0x1195e88 "A+"\0
  CUR = 65541
  LEN = 65544
concat
SV = PV(0xfa8c58) at 0x1171848
  REFCNT = 1
  FLA+GS = (POK,pPOK)
  PV = 0x11a5eb8 "BA+B"\0
  CUR = 65543
  LEN = 65544
string
SV = PV(0xfa8c88) at 0x1114bd0
  REFCNT = 1
  FLA+GS = (POK,pPOK)
  PV = 0x11b5ee8 "BA+B"\0
  CUR = 65543
  LEN = 65552
Perl version 5.025007
  Rate concat string assign
concat 3257/s -- -84% -85%
string 20597/s 532% -- -6%
assign 21920/s 573% 6% --

From which we can see that​:

concat
  CUR = 65543
  LEN = 65544

Which does not leave enough room for the refcount. So a point fix
would appear to be to make sure that concat properly overallocates.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @demerphq

On 30 October 2016 at 10​:30, demerphq <demerphq@​gmail.com> wrote​:

On 30 October 2016 at 09​:57, demerphq <demerphq@​gmail.com> wrote​:

On 30 October 2016 at 09​:51, demerphq <demerphq@​gmail.com> wrote​:

On 29 October 2016 at 09​:46, Leszek Dubiel
<leszek.dubiel@​dubielvitrum.pl> wrote​:

I have tested program below for $ARGV[0] in range of 0 to 2000 (two
twousand).

#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';

my $s = "A"x (2**16 + 5 - $ARGV[0]);
my $cat = 'B' . $s . 'B';
my $spr = sprintf "B%sB", $s;

cmpthese(-1, {
"assign" => sub { my $i=0; $s =~ /./ while $i++ < 100 },
"concat" => sub { my $i=0; $cat =~ /./ while $i++ < 100 },
"string" => sub { my $i=0; $spr =~ /./ while $i++ < 100 }
});
########### end

During this long run​:

   \-\- "concat" was extremely slow in 500 \(five hundred\) cases\, every

fourth run -- $ARGV[0] = 0, 2, 4, 8, 12, 16, ...

  \-\- "assing" was extremely slow for $ARGV\[0\] =  6\,  262\,  518\, 774\,

1030, 1286, 1542, 1798, ...

     \-\- "string" was extremely slow for $ARGV\[0\] = 8\,  264\, 520\,  776\,

1032, 1288, 1544, 1800, ...

My function works on reference to big string, and here is ugly workaround --
check if program is running extremely slow, and add one space to string in
that case (15 seconds)​:

sub ... {

while () {

my $a = \.\.\. \# big text

    \# matching big text \.\.\.
use v5\.10;
state $t = time;
if \(time > $t \+ 15\) \{
    my $x = pos $$a;
    $a \.= " ";
    pos $a = $x;
    $t = time;
\}

}
}

You have not told us your OS, or the version of Perl you are using,
and I cannot replicate this issue, so it is hard to say much.

Can you please provide the output of perl -V, and details about your os, etc.

Actually, playing more, I can replicate in blead on linux (low numbers
are I think due to DEBUGGING build)

$ ./perl -Ilib t.pl 0
Rate concat string assign
concat 3110/s -- -86% -86%
string 21920/s 605% -- -0%
assign 21976/s 607% 0% --

However perl 5.18.4 does not have this issue.

$ perl t.pl 0
Rate assign concat string
assign 62877/s -- -0% -1%
concat 63015/s 0% -- -1%
string 63434/s 1% 1% --

My first guess is that this is an issue with COW and/or malloc.

Well, it is COW, but indirectly.

Modifying your test code to show more detail​:

$ cat t.pl
#!/usr/bin/perl

use strict;
use warnings;
use Benchmark 'cmpthese';
print "Perl version $]\n";
use Devel​::Peek;

my $mod = $ARGV[0] || 0;

my $assign = "A"x (2**16 + 5 - $mod);
my $concat = 'B' . $assign . 'B';
my $string = sprintf "B%sB", $assign;

print STDERR "assign\n";
Dump($assign);
print STDERR "concat\n";
Dump($concat);
print STDERR "string\n";
Dump($string);

cmpthese(-1, {
"assign" => sub { my $i=0; $assign =~ /./ while $i++ < 100 },
"concat" => sub { my $i=0; $concat =~ /./ while $i++ < 100 },
"string" => sub { my $i=0; $string =~ /./ while $i++ < 100 }
});

and then running it like this​:

./perl -Ilib t.pl 0 2>&1 | perl -pe's/A+/A+/g;'

We get this​:

$ ./perl -Ilib t.pl 0 2>&1 | perl -pe's/A+/A+/g;'
assign
SV = PV(0xfa8c38) at 0x10575d8
REFCNT = 1
FLA+GS = (POK,pPOK)
PV = 0x1195e88 "A+"\0
CUR = 65541
LEN = 65544
concat
SV = PV(0xfa8c58) at 0x1171848
REFCNT = 1
FLA+GS = (POK,pPOK)
PV = 0x11a5eb8 "BA+B"\0
CUR = 65543
LEN = 65544
string
SV = PV(0xfa8c88) at 0x1114bd0
REFCNT = 1
FLA+GS = (POK,pPOK)
PV = 0x11b5ee8 "BA+B"\0
CUR = 65543
LEN = 65552
Perl version 5.025007
Rate concat string assign
concat 3257/s -- -84% -85%
string 20597/s 532% -- -6%
assign 21920/s 573% 6% --

From which we can see that​:

concat
CUR = 65543
LEN = 65544

Which does not leave enough room for the refcount. So a point fix
would appear to be to make sure that concat properly overallocates.

Also, we need to remove the exemption for powers-of-2 rule, as it
causes perf degradation too.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Oct 30, 2016

From @demerphq

On 30 October 2016 at 11​:11, demerphq <demerphq@​gmail.com> wrote​:

On 30 October 2016 at 10​:30, demerphq <demerphq@​gmail.com> wrote​:

On 30 October 2016 at 09​:57, demerphq <demerphq@​gmail.com> wrote​:
concat
CUR = 65543
LEN = 65544

Which does not leave enough room for the refcount. So a point fix
would appear to be to make sure that concat properly overallocates.

Also, we need to remove the exemption for powers-of-2 rule, as it
causes perf degradation too.

I have pushed

commit fe546b3
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 11​:02​:57 2016 +0100

  fix #129802​: sv_grow​: remove the overallocation for COW exemption
for powers of 2

  They are just performance bombs waiting to hit the regex engine
  and other code. If someone wants this precise level of management
  then we should provide an API for them to do so.

  Really this just shows the flaw in our current COW implementation.

commit 7fdc4f5
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 10​:56​:36 2016 +0100

  fix perl #129802 - overallocate in concat to ensure we can COW

  Otherwise we get degenerate performance in things like the regex
  engine under certain cases.

The first is potentially controversial. So it might get reverted. But
I consider this ticket closed/fixed.

Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 4, 2016

From @ntyni

On Sun, Oct 30, 2016 at 11​:29​:10AM +0100, demerphq wrote​:

commit fe546b3
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 11​:02​:57 2016 +0100

fix \#129802&#8203;: sv\_grow&#8203;: remove the overallocation for COW exemption

for powers of 2

commit 7fdc4f5
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 10​:56​:36 2016 +0100

fix perl \#129802 \- overallocate in concat to ensure we can COW

The first is potentially controversial. So it might get reverted. But
I consider this ticket closed/fixed.

Many thanks for your work. Just in case you didn't notice, there was
earlier correspondence on this ticket including a comment from Dave with
pretty much the same conclusions.

As this seems to be a performance regression in 5.20 or so (and was
originally reported to Debian as one), is the fix something that could
be considered for the maint-* branches?
--
Niko Tyni ntyni@​debian.org

@p5pRT
Copy link
Author

p5pRT commented Nov 4, 2016

From @tonycoz

On Fri, Nov 04, 2016 at 12​:20​:11PM +0200, Niko Tyni wrote​:

On Sun, Oct 30, 2016 at 11​:29​:10AM +0100, demerphq wrote​:

commit fe546b3
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 11​:02​:57 2016 +0100

fix \#129802&#8203;: sv\_grow&#8203;: remove the overallocation for COW exemption

for powers of 2

commit 7fdc4f5
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 10​:56​:36 2016 +0100

fix perl \#129802 \- overallocate in concat to ensure we can COW

The first is potentially controversial. So it might get reverted. But
I consider this ticket closed/fixed.

Many thanks for your work. Just in case you didn't notice, there was
earlier correspondence on this ticket including a comment from Dave with
pretty much the same conclusions.

As this seems to be a performance regression in 5.20 or so (and was
originally reported to Debian as one), is the fix something that could
be considered for the maint-* branches?

If 7fdc4f5 is backported to maint then whatever fix we end up with
for #129997 will also need to be backported.

Tony

@p5pRT
Copy link
Author

p5pRT commented Nov 4, 2016

From @demerphq

On 4 November 2016 at 13​:53, Tony Cook <tony@​develop-help.com> wrote​:

On Fri, Nov 04, 2016 at 12​:20​:11PM +0200, Niko Tyni wrote​:

On Sun, Oct 30, 2016 at 11​:29​:10AM +0100, demerphq wrote​:

commit fe546b3
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 11​:02​:57 2016 +0100

fix \#129802&#8203;: sv\_grow&#8203;: remove the overallocation for COW exemption

for powers of 2

commit 7fdc4f5
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 10​:56​:36 2016 +0100

fix perl \#129802 \- overallocate in concat to ensure we can COW

The first is potentially controversial. So it might get reverted. But
I consider this ticket closed/fixed.

Many thanks for your work. Just in case you didn't notice, there was
earlier correspondence on this ticket including a comment from Dave with
pretty much the same conclusions.

As this seems to be a performance regression in 5.20 or so (and was
originally reported to Debian as one), is the fix something that could
be considered for the maint-* branches?

If 7fdc4f5 is backported to maint then whatever fix we end up with
for #129997 will also need to be backported.

Unless there is some concern about the power-of-2 issue, my gut
instinct is that there should be no issues backporting these patches.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 4, 2016

From @demerphq

On 4 November 2016 at 11​:20, Niko Tyni <ntyni@​debian.org> wrote​:

On Sun, Oct 30, 2016 at 11​:29​:10AM +0100, demerphq wrote​:

commit fe546b3
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 11​:02​:57 2016 +0100

fix \#129802&#8203;: sv\_grow&#8203;: remove the overallocation for COW exemption

for powers of 2

commit 7fdc4f5
Author​: Yves Orton <demerphq@​gmail.com>
Date​: Sun Oct 30 10​:56​:36 2016 +0100

fix perl \#129802 \- overallocate in concat to ensure we can COW

The first is potentially controversial. So it might get reverted. But
I consider this ticket closed/fixed.

Many thanks for your work.

You are welcome. It is always a pleasure working with you Debian folks.

Just in case you didn't notice, there was
earlier correspondence on this ticket including a comment from Dave with
pretty much the same conclusions.

As this seems to be a performance regression in 5.20 or so (and was
originally reported to Debian as one), is the fix something that could
be considered for the maint-* branches?

Just to repeat what I said in reply to Tony, unless the power-of-2
issue gets reverted I would assume that these patches are fine for
backport.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Mar 27, 2017

From @iabyn

On Tue, Oct 04, 2016 at 09​:42​:51PM +0300, Niko Tyni wrote​:

On Tue, Oct 04, 2016 at 09​:08​:02AM +0100, Dave Mitchell wrote​:

On Mon, Oct 03, 2016 at 01​:15​:27PM -0700, Niko Tyni wrote​:

# New Ticket Created by Niko Tyni
# Please include the string​: [perl #129802]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=129802 >

As reported by Leszek Dubiel in <https://bugs.debian.org/839600>,
there seems to be a regexp performance problem for certain inputs.

This is down to a limitation in the COW implementation. Perl stores the
copy-on-write reference count in the spare byte (if any) just after the \0
at the end of the string. Depending on how the string has been allocated
and/or grown, it may not have a spare byte, and so the string has to be
copied after a match rather than COWed (the copy is so that $1, $2, $`, $&
etc remain with the correct values even if the string is subsequently
modified).

The PADTMP commit is not really relevant - it just happens to alter the
particular route by which a string ended up with SvCUR+1 == SvLEN.

You can see a similar slowdown on old perls (5.16.0 and earlier) if you
add $& somewhere in the test code - then all 3 cases run pathologically
slow.

The whole COW/SvGROW interaction is on my list of things to do.

Many thanks for the explanation. Shouldn't the /n regexp modifier help
in that case? It doesn't seem to.

No, because /n only converts some or all (..)'s into (?​:...)'s. It doesn't
affect $`,$&amp;,$'. So the string still needs to be retained.

--
Please note that ash-trays are provided for the use of smokers,
whereas the floor is provided for the use of all patrons.
  -- Bill Royston

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

2 participants