<div dir="ltr">Hi Levente,<div class="gmail_extra"><br><div class="gmail_quote">On Tue, Feb 28, 2017 at 10:44 AM, Levente Uzonyi <span dir="ltr"><<a href="mailto:leves@caesar.elte.hu" target="_blank">leves@caesar.elte.hu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In case someone would like to defend the performance of #~~ and #notNil, here's a little benchmark I just wrote:<br>
<br>
| base ifNilIfNotNil notIdentical notEqual notNil |<br>
Smalltalk garbageCollect.<br>
base := (1 to: 5) collect: [ :run |<br>
        [ 1 to: 100000000 do: [ :i | ] ] timeToRun ].<br>
<br>
ifNilIfNotNil := (1 to: 5) collect: [ :run |<br>
        [ 1 to: 100000000 do: [ :i | i ifNil: [ false ] ifNotNil: [ true ] ] ] timeToRun ].<br>
<br>
notIdentical := (1 to: 5) collect: [ :run |<br>
        [ 1 to: 100000000 do: [ :i | i ~~ nil ] ] timeToRun ].<br>
<br>
notEqual := (1 to: 5) collect: [ :run |<br>
        [ 1 to: 100000000 do: [ :i | i ~= nil ] ] timeToRun ].<br>
<br>
<br>
notNil := (1 to: 5) collect: [ :run |<br>
        [ 1 to: 100000000 do: [ :i | i notNil ] ] timeToRun ].<br>
<br>
{<br>
        #ifNilIfNotNil -> ifNilIfNotNil.<br>
        #notIdentical -> notIdentical.<br>
        #notEqual -> notEqual.<br>
        #notNil -> notNil<br>
}<br>
        replace: [ :each |<br>
                each key -> (each value average - base average) asFloat ];<br>
        sort: #value ascending<br>
<br>
"{#ifNilIfNotNil->73.6 . #notNil->336.8 . #notIdentical->511.6 . #notEqual->3354.0}"<br>
<br>
So it's 4.5x faster than #notNil and 7x faster than #~~ on 64-bit Spur on Linux. Once we have jitted #~~, I'll change the code again.</blockquote><div><br></div><div>IIRC, all one needs to get jitted #~~ is to store #~~ in place of blockCopy: in the specialSelectors array and recompile all senders of #~~.  You may need to collect all senders of #~~ before you make the swap since putting it in the specialSelectors array may confuse allReferencesTo: et al.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="HOEnZb"><font color="#888888">Levente</font></span><div class="HOEnZb"><div class="h5"><br>
<br>
<br>
On Tue, 28 Feb 2017, <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> wrote:<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Levente Uzonyi uploaded a new version of Collections to project The Trunk:<br>
<a href="http://source.squeak.org/trunk/Collections-ul.739.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/trunk<wbr>/Collections-ul.739.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: Collections-ul.739<br>
Author: ul<br>
Time: 28 February 2017, 7:34:55.711173 pm<br>
UUID: 66c6ecf2-71bf-4e7d-80e6-5ace72<wbr>fa19ba<br>
Ancestors: Collections-ul.738<br>
<br>
- use micro optimization for #~~ and #notNil in common collection methods<br>
- reuse one of the OrderedCollections in RunArray >> #scanFrom:<br>
- two other minor tweaks in KeyedSet<br>
- removed accidentally commited Set >> #includes2:<br>
<br>
=============== Diff against Collections-ul.738 ===============<br>
<br>
Item was changed:<br>
 ----- Method: Dictionary>>includesKey: (in category 'testing') -----<br>
 includesKey: key<br>
        "Answer whether the receiver has a key equal to the argument, key."<br>
<br>
+       (array at: (self scanFor: key)) ifNil: [ ^false ] ifNotNil: [ ^true ]!<br>
-        ^(array at: (self scanFor: key)) notNil!<br>
<br>
Item was changed:<br>
 ----- Method: KeyedSet>>includesKey: (in category 'testing') -----<br>
 includesKey: key<br>
<br>
+       (array at: (self scanFor: key)) ifNil: [ ^false ] ifNotNil: [ ^true ]!<br>
-       ^ (array at: (self scanFor: key)) notNil!<br>
<br>
Item was changed:<br>
 ----- Method: KeyedSet>>remove:ifAbsent: (in category 'removing') -----<br>
 remove: oldObject ifAbsent: aBlock<br>
<br>
        | index |<br>
        index := self scanFor: (keyBlock value: oldObject).<br>
+       (array at: index) ifNil: [ ^ aBlock value ].<br>
-       (array at: index) == nil ifTrue: [ ^ aBlock value ].<br>
        array at: index put: nil.<br>
        tally := tally - 1.<br>
        self fixCollisionsFrom: index.<br>
        ^ oldObject!<br>
<br>
Item was changed:<br>
 ----- Method: KeyedSet>>removeKey:ifAbsent: (in category 'removing') -----<br>
 removeKey: key ifAbsent: aBlock<br>
<br>
        | index obj |<br>
        index := self scanFor: key.<br>
+       obj := (array at: index) ifNil: [ ^ aBlock value ].<br>
-       (obj := array at: index) == nil ifTrue: [ ^ aBlock value ].<br>
        array at: index put: nil.<br>
        tally := tally - 1.<br>
        self fixCollisionsFrom: index.<br>
        ^ obj enclosedSetElement!<br>
<br>
Item was changed:<br>
 ----- Method: RunArray class>>scanFrom: (in category 'instance creation') -----<br>
 scanFrom: strm<br>
        "Read the style section of a fileOut or sources file.  nextChunk has already been done.  We need to return a RunArray of TextAttributes of various kinds.  These are written by the implementors of writeScanOn:"<br>
        | runs values attrList char |<br>
        (strm peekFor: $( ) ifFalse: [^ nil].<br>
        runs := OrderedCollection new.<br>
        [strm skipSeparators.<br>
         strm peekFor: $)] whileFalse:<br>
                [runs add: (Number readFrom: strm)].<br>
        values := OrderedCollection new.        "Value array"<br>
        attrList := OrderedCollection new.      "Attributes list"<br>
        [(char := strm peek) == nil] whileFalse: [<br>
                (char isSeparator or: [ char = $!! ])<br>
                        ifTrue: [ "n.b. Skip $!! to meet expectations of RunArrayTest>>testScanFromTrai<wbr>ler.<br>
                                        The example string used in that test does not seem to match the implemention<br>
                                        of the fileOut serialization, but the test may be right and the implementation<br>
                                        wrong. In any case, relax the parsing here to meet the test expectations, and to<br>
                                        be more consistent with the original version of this method that assumed any<br>
                                        unexpected charater to be a separator. -dtl Jan 2014"<br>
                                strm next "space, cr do nothing"]<br>
                        ifFalse: [char == $,<br>
                                        ifTrue: [strm next.<br>
                                                values add: attrList asArray.<br>
+                                               attrList reset ]<br>
-                                               attrList := OrderedCollection new]<br>
                                        ifFalse: [attrList add:  (TextAttribute newFrom: strm)]<br>
                                ]<br>
                ].<br>
        values add: attrList asArray.<br>
        ^ self runs: runs asArray values: (values copyFrom: 1 to: runs size) asArray<br>
 "<br>
 RunArray scanFrom: (ReadStream on: '(14 50 312)f1,f1b,f1LInteger +;i')<br>
 "!<br>
<br>
Item was removed:<br>
- ----- Method: Set>>includes2: (in category 'testing') -----<br>
- includes2: anObject - -       ^((array at: (self scanFor: anObject)) == nil) not!<br>
<br>
Item was changed:<br>
 ----- Method: WeakIdentityDictionary>>includ<wbr>esKey: (in category 'testing') -----<br>
 includesKey: key<br>
        "Answer whether the receiver has a key equal to the argument, key."<br>
<br>
+       (array at: (self scanFor: key))<br>
+               ifNil: [<br>
+                       "it just has been reclaimed"<br>
+                       ^false]<br>
+               ifNotNil: [ :element |<br>
+                       element == vacuum<br>
+                               ifTrue: [ ^false ]<br>
+                               ifFalse: [ ^true ] ]!<br>
-       ^(array at: (self scanFor: key))<br>
-               ifNil:<br>
-                       ["it just has been reclaimed"<br>
-                       false]<br>
-               ifNotNil: [:element | element ~~ vacuum]!<br>
<br>
Item was changed:<br>
 ----- Method: WeakSet>>includes: (in category 'testing') -----<br>
 includes: anObject<br>
<br>
        (array at: (self scanFor: anObject))<br>
                ifNil: [ ^false ]<br>
+               ifNotNil: [ :object |<br>
+                       object == flag<br>
+                               ifTrue: [ ^false ]<br>
+                               ifFalse: [ ^true ] ]!<br>
-               ifNotNil: [ :object | ^object ~~ flag ]!<br>
</blockquote>
<br>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="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>