in reply to Don't treat your numbers as strings, or Interpolation is worse than you might think

It's an optimization. You asked perl to generate the string form of those number and it cached that. It shouldn't be any slower to access because both values are known to perl to have a valid number so it just uses the existing stored number. The upgrade caused your values in increase in size. Maybe it's a CPU cache thing. I'm just guessing because I expect the code path you're benchmarking to be identical.

In the following examples I've slimmed down the output a bit by removing REFCNT, CUR, LEN, and addresses. They didn't add anything but clutter. Run the code yourself if you want to see the extra goop.

A plain number. IOK says this has a valid number value stored.

perl -MDevel::Peek -e '$x=42;Dump $x' SV = IV(0x ) at 0x FLAGS = (IOK,pIOK) IV = 42

A stringified number. IOK and POK say it has valid integer and string values.

perl -MDevel::Peek -e '$x=42;print "$x";Dump $x'' SV = PVIV(0x ) at 0x FLAGS = (IOK,POK,pIOK,pPOK) IV = 42 PV = 0x "42"\0

A plain string. POK says it has a valid string value.

perl -MDevel::Peek -e '$x="42";Dump $x' SV = PV(0x ) at 0x FLAGS = (POK,pPOK) PV = 0x "42"\0

Watch the upgrade in action. Notice that the IV(0x....) address changed to PVIV(0x...). This tells you that the guts are now living somewhere else in memory. The old location wasn't big enough to be used as-is so it was copied to a new location (the old location made available again). The "at 0x813ab4c" that remained constant told you it was the same value as far as your user code could tell. You never knew any magic had happened.

perl -MDevel::Peek -e '$x=42;Dump $x;print NOWHERE "$x";Dump $x' SV = IV(0x815544c) at 0x812ab4c FLAGS = (IOK,pIOK) IV = 42 SV = PVIV(0x812c080) at 0x812ab4c FLAGS = (IOK,POK,pIOK,pPOK) IV = 42 PV = 0x8150890 "42"\0

⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

  • Comment on Re: Don't treat your numbers as strings, or Interpolation is worse than you might think
  • Select or Download Code

Replies are listed 'Best First'.
Re^2: Don't treat your numbers as strings, or Interpolation is worse than you might think
by Joost (Canon) on Jul 22, 2006 at 15:01 UTC
    Maybe it's a CPU cache thing. I'm just guessing because I expect the code path you're benchmarking to be identical.
    I would guess it is because both the number AND the string representation are copied:

    perl -MDevel::Peek -e'$x=42; "$x"; $y = $x; Dump $y' SV = PVIV(0x814e9a8) at 0x814d518 REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) IV = 42 PV = 0x8168e70 "42"\0 CUR = 2 LEN = 4
    In summary - the slowdown effect should only be noticable when you're copying the variables: as you implied, using arithmatic on numbers that are also stringified should not slow down (much).

    update: Ieronim, the issue is that when you stringify a number, perl stores both representations in the variable.

    When you copy it, perl doesn't know whether you're going to use the copies as string or numbers, so it copies the whole variable (since that should be faster than copying only one representation and converting it later).

      ++Joost and diotalevi. Thank you :) After reading the documentation of Devel::Peek i understood that among others there are three types of simple scalar value in Perl—PV (string), IV (integer) and PVIV (both). Of course i tried to compare the speed of them (actually, as you noticed, the speed of copying them). And I got a expected result:
      Rate PVIV PV IV PVIV 2065/s -- -1% -64% PV 2084/s 1% -- -64% IV 5806/s 181% 179% --
      The difference between PV and PVIV is so small that i did not notice it in my benchmarks and thought that the numbers are CONVERTED to strings :)

      The code of the benchmark is here.

      UPD: updated according to diotalevi's note :)

           s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print

        There's more than just that. Check out the nice ASCII art in B and the pretty pictures at PerlGuts Illustrated.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        It's a really interesting meditation, thanks !

        it left me with one question :
        when you type :
        print "ARRAY: @ary2\n"; # IV -> PVIV
        it converts your IV to PVIV.

        But, I would have thinked then that this :
        $_ += 0 foreach @ary2;
        executed on a PVIV, would keep it a PVIV. Why does it reverse it to an IV. It's a kind of rule internally ? When you make a numeric operation on a scalar, it convert it into an IV ? I mean, if there is a type which carry both (PVIV), it could have continue with it ? No ? Are there reasons other than the idea of using less memory/less timecode ?

        Thanks,
        Marsel

      Joost, the copy was done before the benchmark. Its the operations on the copied values that's slower. I assume perl is treating both as numbers because both have the IOK flag set which also means I think both have identical code paths. I think then, the only difference is that these values are spaced out more in memory and consume more memory. To code, I expect there should be no difference. In reality, the only thing I can guess is that it has something to do with CPU caches or any of that nonsense that I'm not sure how to reason about.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊