<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>