<div dir="ltr">Hi Benoit,<div class="gmail_extra"><br><div class="gmail_quote">On Fri, Jan 6, 2017 at 11:59 PM, Benoit St-Jean <span dir="ltr"><<a href="mailto:bstjean@yahoo.com" target="_blank">bstjean@yahoo.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:'times new roman','new york',times,serif;font-size:16px"><div id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100129" dir="ltr"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168">Hello guys,<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100327"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100328">A few questions/comments/remarks about integer arithmetic and bit operations.  And I guess many of my interrogations most likely concern the guys building the VM/primitives...<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100329"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100330">I'm working on a chess engine that will rely heavily on bitboard manipulations, i.e. lots of integer arithmetic with bit operations.  I was comparing the 32bit & 64bit Spur VM for Squeak & Pharo (I want the chess engine to be portable on Squeak & Pharo).  As I pointed out earlier on on the Squeak-dev  mailing list in october 2016, there are a few things that look strange to me and/or that I do not understand.<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100331"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100332">1) #bitXor: performs the same on the 32bit & 64bit VM for LargePositiveInteger.  BUT, on average, #bitXor: is 15 (fifteen) times *slower* on LargePositiveInteger than with SmallInteger, for both 32 & 64 bit VM/Image. Besides, with SmallInteger, #bitXor: is 4.5 faster on 32bit as compared to 64bit!!  <br></span></div><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104406"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168"><br></span></div><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104407"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168">You can test (on 32bit & 64bit) that with the following snippet:<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100333"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100334">| small1 small2 small3 large1 large2 n timeSmall timeLarge |<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100335">small1 := 2r1111111111111111. "65535,  (1<<16)-1"<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100336">small2 := (1 << 30) - 1. "Largest SmallInteger on 32bit VM/Image, SmallInteger maxVal"<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100337">small3 :=  1152921504606846975. "Largest Integer on 64bit VM/Image, SmallInteger maxVal"<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100338">large1 := (1 << 64)-1. "64 bits set to 1" <br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100339">large2 := (1 << 80)-1. "80 bits set to 1"<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100340"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100341">n := 100000000.<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100342">timeSmall := Time millisecondsToRun: [n timesRepeat: [ small1 bitXor:  small2]].<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100343">timeLarge := Time millisecondsToRun: [n timesRepeat: [ large1 bitXor:  large2]].<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100344">Transcript cr;show: 'Time LargePositiveInteger : ', timeLarge printString.<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100345">Transcript cr;show: 'Time SmallInteger : ', timeSmall printString.<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100346"></span></div></div></div></blockquote><div><br></div><div>It's really important when running micro-benchmarks like this to minimize or eliminate other costs.  So you should unwind your inner loops, to at least to ten repetitions or more.  And it's wise to measure the time taken for an empty loop.  In these cases I'd consider comparing a loop containing 10 instances of the operation against one containing one, e.g. for a time in seconds you could use</div><div><br></div><div><div><br></div><div>| small1 small2 n |</div><div>n := 1000000.</div><div>small1 := SmallInteger minVal.</div><div>small2 := SmallInteger maxVal.</div><div>(Time millisecondsToRun: [1 to: n do: [:i| small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2. small1 bitXor:  small2]]) - (Time millisecondsToRun: [1 to: n do: [:i| small1 bitXor:  small2]]) / 10000.0 / n </div><div><br></div><div>When I do this I get 2.4e-9 for 64-bit Squeak and 2.7e-9 for 32-bit Squeak.  Note that I used 1 to: n do: [:ignored| rather than timesRepeat: because I know its inlined and timesRepeat: isn't always.  But in any case I don't see the large difference in SmallInteger operation times that you do.  Could you repeat your measurements taking something similar to my approach?</div></div><div><span style="color:rgb(0,0,0);font-family:'times new roman','new york',times,serif;font-size:16px"><br></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:'times new roman','new york',times,serif;font-size:16px"><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104407"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100347"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100348">As was pointed out by Nicolas Cellier in a private communication, one workaround is to add the method #bitXor: in the class LargePositiveInteger to get a 3x performance boost.  Nicolas recommended the following code:<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100349"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100350">LargePositiveInteger>>bitXor: arg<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100351">    <primitive:36><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100352">    ^super bitXor: arg<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100353">    <br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100354">It's all good and nice (and I do get a 3x speedup, in 32&64 bit) but then I wonder in which respect primitive 36 is different from the one LargePositiveInteger usually inherits from Integer :<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100355"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100356">(Integer>>bitXor:)<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100357"><primitive: 'primDigitBitXor' module:'LargeIntegers'><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100358"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100359">Why does Nicolas' workaround is able to do the job (calling primitive 36) when there is already a primitive for the exact thing (<primitive: 'primDigitBitXor' module:'LargeIntegers'>) ? Is this duplicate code or there is a reason for this?  And why is the primDigitBitXor primitive so slow as compared to primitive 36? <br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100360"></span></div></div></div></blockquote><div><br></div><div>Primitive 36 deals with only 64-bit values (up to 8 byte LargeIntegers).   <span style="color:rgb(0,0,0);font-family:'times new roman','new york',times,serif;font-size:16px"><primitive: 'primDigitBitXor' module:'LargeIntegers'> deals with arbitrary sized large integers.</span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:'times new roman','new york',times,serif;font-size:16px"><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104407"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100361">2) One would normally expect the 64bit VM to be faster than the 32bit VM.  That's true in all cases except...  Well, first, some numbers (Test case attached to this email if you want to reproduce)<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100362"></span></div></div></div></blockquote><div><br></div><div>It depends on the computation.  One should expect the 64-bit VM to be faster for certain kinds of arithmetic because it can do more in one operation, e.g. 60-bit arithmetic should be much faster in 64-bits than in 32-bits, most floating point should be much faster because of the immediate floating-point representation.  But consider a purely symbolic computation, say tree walking.  The 64-bit version has to move twice as much data as the 32-bit version, so if the working set is large but amenable to execution in 32-bits one would expect the 32-bit application to run faster because it accesses half the data.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:'times new roman','new york',times,serif;font-size:16px"><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104407"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100363">32bit<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100364">Number of #allMask: per second : 6.20M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100365">Number of #anyMask: per second : 7.17M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100366">Number of #bitAnd: per second : 8.45M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100367">Number of #bitAt: per second : 55.15M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100368">Number of #bitAt:put: per second : 37.22M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100369">Number of #bitClear: per second : 5.18M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100370">Number of #bitInvert per second : 6.53M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100371">Number of #bitOr: per second : 9.18M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100372">Number of #bitXor: per second : 8.97M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100373">Number of #highBit per second : 43.23M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100374">Number of #<< per second : 11.34M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100375">Number of #lowBit per second : 69.44M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100376">Number of #noMask: per second : 7.40M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100377">Number of #>> per second : 12.36M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100378"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100379">64bit<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100380">Number of #allMask: per second : 10.26M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100381">Number of #anyMask: per second : 10.37M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100382">Number of #bitAnd: per second : 17.00M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100383">Number of #bitAt: per second : 15.89M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100384">Number of #bitAt:put: per second : 10.36M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100385">Number of #bitClear: per second : 6.44M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100386">Number of #bitInvert per second : 9.11M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100387">Number of #bitOr: per second : 18.45M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100388">Number of #bitXor: per second : 15.38M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100389">Number of #highBit per second : 7.66M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100390">Number of #<< per second : 10.50M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100391">Number of #lowBit per second : 13.49M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100392">Number of #noMask: per second : 11.47M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100393">Number of #>> per second : 10.52M<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100394"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100395">There are a few surprises here.  First, #bitAt:, #bitAt:put:, #highBit and #lowBit are a *lot faster* on the 32bit VM than on the 64bit VM! Does anyone have an explanation for this?  Is this normal?<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100396"></span></div></div></div></blockquote><div><br></div><div>Can you rerun the numbers using my approach before we attempt to answer this?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div><div style="color:rgb(0,0,0);background-color:rgb(255,255,255);font-family:'times new roman','new york',times,serif;font-size:16px"><div dir="ltr" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104407"><span id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100168"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100397">The other surprise is that #>> and #<< seem to be about the same speed on both VM.  Any reason why the 64bit version isn't faster than the 32bit one?<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100398"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100399">3) I was surprised to find out that SmallInteger>>#maxVal wasn't a constant (or the same on both VM).  It's (1<<60)-1 on the 64bit VM and (1<<30)-1 on the 32bit VM.  So, be warned if your code depends on SmallInteger>>#maxVal for some reason!<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100400"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100401">4) Is there any rationale/reason/explanation as to why, in Pharo, LargePositiveInteger inherits from the class LargeInteger (which doesn't exist in Squeak) ?<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100402"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100403">Thanks in advance.<br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100404"><br id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_100405"></span></div><div id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104606"> </div><div class="gmail-m_-1770124332305820750signature" id="gmail-m_-1770124332305820750yui_3_16_0_ym19_1_1483683232152_104602">----------------- <br>Benoît St-Jean <br>Yahoo! Messenger: bstjean
 <br>Twitter: @BenLeChialeux
 <br>Pinterest: benoitstjean
 <br>Instagram: Chef_Benito<br>IRC: lamneth
 <br>Blogue: <a href="http://endormitoire.wordpress.com" target="_blank">endormitoire.wordpress.com</a>
 <br>"A standpoint is an intellectual horizon of radius zero".  (A. Einstein)</div></div></div><br><br>
<br></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div>
</div></div>