FAQ

On 6/14/06, Rafael Garcia-Suarez wrote:
demerphq wrote:
Hmm, i cant recreate this. The line in question is debugging related,
and I dont see what could result in a segfault after the "Freeing REx"
message has been emitted...

I wonder what compile options you are building under...
The default ones.

This appears to fix :

--- regcomp.h (révision 7997)
+++ regcomp.h (copie de travail)
@@ -570,7 +570,7 @@

/* Compile */
#define DEBUG_COMPILE_r(x) DEBUG_r( \
- if (SvIV(re_debug_flags) & RE_DEBUG_COMPILE_MASK) x )
+ if (re_debug_flags && SvIV(re_debug_flags) & RE_DEBUG_COMPILE_MASK) x )
#define DEBUG_PARSE_r(x) DEBUG_r( \
if (SvIV(re_debug_flags) & RE_DEBUG_COMPILE_PARSE) x )
#define DEBUG_OPTIMISE_r(x) DEBUG_r( \
End of patch

(other DEBUG_.*_r macros should probably be adapted too)

I wonder what set re_debug_flags to NULL. Any idea ?
During global destruction get_sv() can return null.

Nicholas spotted this and applied a small patch that resolved a bit of
the problem, but unfortunately I didnt connect the two together until
your reply illuminated the source of the problem.

Anyway, the solution is to convert the macros to operate on a UV and
not on the SV directly and let the GET_RE_DEBUG_FLAGS handle setting
up the UV correctly assuming get_sv returns something useful.

Also, i noticed that Benchmark sometimes goes into an infinte loop on
test 67 of lib/Benchmark.t, the problem is that its possible for the
empty loop to take the same time or longer than the item being
benchmarked. In this case there are at least two loops in countit()
that go infinite as they assume that timeit() will return positive
results. Here is the test code in question:

my $start = times;
my $chart = cmpthese( -0.1, { a => "++\$i", b => "\$i = sqrt(\$i++)" } ) ;
my $end = times;
select(STDOUT);
ok (($end - $start) > 0.05, "benchmarked code ran for over 0.05 seconds");

The timing of ++$i is so close to the time of an empty loop that we
can end up in an infinite loop.

As a block to this I have added some heuristics to prevent an infinite
loop. If the timing loops get a negative or zero timing from timeit()
16 times in a row they will bail with an error that the benchmark is
impossible to complete.

I will say however that [ersonally I think that this is the wrong
approach: Timing the empty loop and subtracting it from the run time
of the benchmarked code is fraught with errors. If the load average
changes during the timing of the empty loop the benchmark is basically
garbage, if the run time of the empty loop is very close or slower due
to load reasons than the timing of the actual code, then there is the
possibility of an infinite loop. If somebody ever hacks perl to
optimise away useless code such as empty loops or sub calls to
contentless subs then the empty loop timings are toast anyway.

Id say that the best thing to do would be to remove the empty loop
timing stuff from the benchmark outright. It would eliminate the pesky
infinite loop, it would improve confidence in the benchmarks, and it
would have a minimal cost as most benchmarking is comparative anyway,
so removing the empty loop is irrelevent to it. The only thing that
would be affected is that the timing of a routine would include the
cost of execution the timing loop itself, something that I dont think
many people would care about.

Yves


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

Search Discussions

  • Rafael Garcia-Suarez at Jun 14, 2006 at 12:12 pm

    demerphq wrote:
    I wonder what set re_debug_flags to NULL. Any idea ?
    During global destruction get_sv() can return null.

    Nicholas spotted this and applied a small patch that resolved a bit of
    the problem, but unfortunately I didnt connect the two together until
    your reply illuminated the source of the problem.

    Anyway, the solution is to convert the macros to operate on a UV and
    not on the SV directly and let the GET_RE_DEBUG_FLAGS handle setting
    up the UV correctly assuming get_sv returns something useful.
    Thanks, applied as change #28393.
  • Demerphq at Jun 14, 2006 at 12:33 pm

    On 6/14/06, Rafael Garcia-Suarez wrote:
    demerphq wrote:
    I wonder what set re_debug_flags to NULL. Any idea ?
    During global destruction get_sv() can return null.

    Nicholas spotted this and applied a small patch that resolved a bit of
    the problem, but unfortunately I didnt connect the two together until
    your reply illuminated the source of the problem.

    Anyway, the solution is to convert the macros to operate on a UV and
    not on the SV directly and let the GET_RE_DEBUG_FLAGS handle setting
    up the UV correctly assuming get_sv returns something useful.
    Thanks, applied as change #28393.
    Heres a tweak, and a fix to make OFFSETS not depend on DUMP.

    Cheers,
    yves

    --
    perl -Mre=debug -e "/just|another|perl|hacker/"
  • Rafael Garcia-Suarez at Jun 14, 2006 at 2:59 pm

    demerphq wrote:
    On 6/14/06, Rafael Garcia-Suarez wrote:
    demerphq wrote:
    I wonder what set re_debug_flags to NULL. Any idea ?
    During global destruction get_sv() can return null.

    Nicholas spotted this and applied a small patch that resolved a bit of
    the problem, but unfortunately I didnt connect the two together until
    your reply illuminated the source of the problem.

    Anyway, the solution is to convert the macros to operate on a UV and
    not on the SV directly and let the GET_RE_DEBUG_FLAGS handle setting
    up the UV correctly assuming get_sv returns something useful.
    Thanks, applied as change #28393.
    Heres a tweak, and a fix to make OFFSETS not depend on DUMP.
    Thanks, tweaked as #28394.
  • Jarkko Hietaniemi at Jun 14, 2006 at 8:07 pm

    I will say however that [ersonally I think that this is the wrong
    approach: Timing the empty loop and subtracting it from the run time
    of the benchmarked code is fraught with errors. If the load average
    changes during the timing of the empty loop the benchmark is basically
    garbage, if the run time of the empty loop is very close or slower due
    If one measures CPU time (user + sys) load average is much less of an
    issue. Not completely a non-issue (a heavily loaded system has more
    I/O interrupts, less memory, etc.) but CPU seconds are pretty reliable
    measure of the time spent unless the system is really on its knees
    and/or overcommitted.
    to load reasons than the timing of the actual code, then there is the
    possibility of an infinite loop.
    Care to elaborate on this a bit? I think in the general case your
    claim is wrong -- one certainly HAS TO subtract the time taken by
    the benchmarking harness, especially so for shorter tests.

    $ time perl -le 'for($i=0;$i<1e6;$i++){}'
    r 0,21s u 0,19s s 0,01s 97%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){}'
    r 0,26s u 0,24s s 0,01s 97%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/fii|foo/}'
    r 15,60s u 15,59s s 0,00s 99%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/f(ii|oo)/}'
    r 1,12s u 1,10s s 0,01s 98%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/f(?:ii|oo)/}'
    r 1,10s u 1,08s s 0,01s 99%
    $

    Without subtracting the empty loop you would end up thinking the
    f(?:ii|oo) is about 17 times faster than the /fii|foo/, when in
    fact it is only 14 times faster. Not a massive difference here,
    but I am certain it is easy to find more dramatic examples, especially
    when some method A being tested is very, very fast, compared to some
    other method B being tested.

    If we had some blisteringly fast way of running a code block N
    times in Perl (Ruby, anyone...), we could use that instead of the
    silly loop, of course.
    If somebody ever hacks perl to
    optimise away useless code such as empty loops or sub calls to
    contentless subs then the empty loop timings are toast anyway.
    'for($i=0;$i<1e6;$i++){}print $i'

    Optimize that. Yes, I know, some compilers can do pretty amazing
    stuff... But I think Perl has more pressing speed needs than
    recognizing that as equivalent of $i=1e6.
    Id say that the best thing to do would be to remove the empty loop
    timing stuff from the benchmark outright. It would eliminate the pesky
    infinite loop, it would improve confidence in the benchmarks, and it
    If a loop is wrongly getting infinite the right fix is to avoid it
    becoming infinite, not to remove the timing of the empty loop.
    would have a minimal cost as most benchmarking is comparative anyway,
    so removing the empty loop is irrelevent to it. The only thing that
    would be affected is that the timing of a routine would include the
    cost of execution the timing loop itself, something that I dont think
    many people would care about.
  • Demerphq at Jun 15, 2006 at 6:55 am

    On 6/14/06, Jarkko Hietaniemi wrote:
    I will say however that [ersonally I think that this is the wrong
    approach: Timing the empty loop and subtracting it from the run time
    of the benchmarked code is fraught with errors. If the load average
    changes during the timing of the empty loop the benchmark is basically
    garbage, if the run time of the empty loop is very close or slower due
    If one measures CPU time (user + sys) load average is much less of an
    issue. Not completely a non-issue (a heavily loaded system has more
    I/O interrupts, less memory, etc.) but CPU seconds are pretty reliable
    measure of the time spent unless the system is really on its knees
    and/or overcommitted.
    to load reasons than the timing of the actual code, then there is the
    possibility of an infinite loop.
    Care to elaborate on this a bit? I think in the general case your
    claim is wrong -- one certainly HAS TO subtract the time taken by
    the benchmarking harness, especially so for shorter tests.

    $ time perl -le 'for($i=0;$i<1e6;$i++){}'
    r 0,21s u 0,19s s 0,01s 97%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){}'
    r 0,26s u 0,24s s 0,01s 97%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/fii|foo/}'
    r 15,60s u 15,59s s 0,00s 99%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/f(ii|oo)/}'
    r 1,12s u 1,10s s 0,01s 98%
    $ time perl -le '$_="a"x1e2."fox";for($i=0;$i<1e6;$i++){/f(?:ii|oo)/}'
    r 1,10s u 1,08s s 0,01s 99%
    $

    Without subtracting the empty loop you would end up thinking the
    f(?:ii|oo) is about 17 times faster than the /fii|foo/, when in
    fact it is only 14 times faster. Not a massive difference here,
    but I am certain it is easy to find more dramatic examples, especially
    when some method A being tested is very, very fast, compared to some
    other method B being tested.
    Color me unconvinced. First off, we do a empty loop timing every time.
    So the value being subtracted from A is not going to be the same value
    subtracted from B.

    I dont see why A - A' compared to B - B' is better than A compared to B.

    Also, i dont think its important to know exactly how many times faster
    a snippet of code is when the overhead of the benchmark is removed.
    Its sufficient to know that both algorithms are paying the same price
    to the piper and that one is faster.

    (And of course in blead /f(?:ii|oo)/ and /fii|foo/ are going to result
    in the same regex program so should benchmark as being the same
    speed.)

    As for inifinite loops on Win32 at least when i run Benchmark.pm I can
    break it by adding an assert that $benchmark->[1]+$benchmark[2] must
    be >0. In my Benchmark.pm patch uncomment the lines in timediff().

    I can also make it infinite loop by forcing timeit() to return a 0
    second benchmark, which can and does happen naturally.

    So timediff() when running Benchmark.t returns benchmark objects with
    a zero or negative timinging total. When this gets fed into the logic
    in countit() it results in an inifinite loop.

    Look throught the Win32 FAIL smokes, if you see Benchmark crapping out
    arround test #60 or #67 then the failure is due to an infinite loop.
    If we had some blisteringly fast way of running a code block N
    times in Perl (Ruby, anyone...), we could use that instead of the
    silly loop, of course.
    If somebody ever hacks perl to
    optimise away useless code such as empty loops or sub calls to
    contentless subs then the empty loop timings are toast anyway.
    'for($i=0;$i<1e6;$i++){}print $i'

    Optimize that. Yes, I know, some compilers can do pretty amazing
    stuff... But I think Perl has more pressing speed needs than
    recognizing that as equivalent of $i=1e6.
    Agreed. My point was just that there are a host of ways that the empty
    loop timing can go to hell, and one of them is new optimisations in
    perl.
    Id say that the best thing to do would be to remove the empty loop
    timing stuff from the benchmark outright. It would eliminate the pesky
    infinite loop, it would improve confidence in the benchmarks, and it
    If a loop is wrongly getting infinite the right fix is to avoid it
    becoming infinite, not to remove the timing of the empty loop.
    Well, i figured this wouldnt be an uncommon position, hence my patch
    is to "fix" the infinite loops and not to remove them...

    :-)

    Anyway,
    Cheers,
    Yves



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

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupperl5-porters @
categoriesperl
postedJun 14, '06 at 11:55a
activeJun 15, '06 at 6:55a
posts6
users3
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase