[squeak-dev] The Inbox: Kernel-fn.1151.mcz
Chris Cunningham
cunningham.cb at gmail.com
Thu Mar 22 04:00:53 UTC 2018
So, speed:
current (^aBoolean or ^aBoolean not) - standard
~~ 71% faster
ul's xor: (aBoolean ifTrue: [^] ifFalse: [^]) 7% slower
em's xor: ( ^aBoolean ifTrue: [] ifFalse: []) 22% slower
ul's block xor: (aBoolean value ifTrue: [^] ifFalse: [^]) 42% slower
em's block xor: (^aBoolean value ifTrue: [] ifFalse: []) 65% slower
fn's xor: (^ alternativeBlock value or ^alternativeBlock value not) 84%
slower
I find it weird that the extra ifTrue:ifFalse: call after the value
actually makes the method faster. Weird.
But it does make it more consistent/right - it only works when the receiver
and value of the argument are both booleans - with the right results.
Note that even though the percentages are fairly large, the actual time to
run 10,000,000 of these checks took right about 3 second for the slowest of
these - once I've removed the 6 seconds of the loop overhead. Still fast.
Will be moving to trunk shortly, using this style: ^aBoolean value ifTrue:
[] ifFalse: []
It just feels more natural. Feel free to adjust if desired.
-cbc
On Wed, Mar 21, 2018 at 7:20 PM, Eliot Miranda <eliot.miranda at gmail.com>
wrote:
>
>
> On Wed, Mar 21, 2018 at 5:15 PM, Levente Uzonyi <leves at caesar.elte.hu>
> wrote:
>
>> On Wed, 21 Mar 2018, Eliot Miranda wrote:
>>
>>
>>>
>>> On Wed, Mar 21, 2018 at 2:48 PM, Levente Uzonyi <leves at caesar.elte.hu>
>>> wrote:
>>> On Tue, 20 Mar 2018, Chris Cunningham wrote:
>>>
>>> Hi. Reopening this thread - probably tomorrow will
>>> implement 'better' solution (with documentation).
>>>
>>> On Sat, Feb 10, 2018 at 12:03 PM, Tobias Pape <
>>> Das.Linux at gmx.de> wrote:
>>>
>>> > On 10.02.2018, at 20:36, Tony Garnock-Jones <
>>> tonyg at leastfixedpoint.com> wrote:
>>> >
>>> > On 02/10/2018 07:02 PM, Levente Uzonyi wrote:
>>> >> So,
>>> >> a perform: {#or:. #xor:. #and:} atRandom with: b
>>> >> would just work for that imaginary interpreter if b
>>> were a Boolean.
>>> >
>>> > Yes, that "interpreter" works just fine today, if b
>>> is a Boolean. It's
>>> > the case where b is a Boolean-producing expression -
>>> such as in a "lazy"
>>> > interpreter - that doesn't work without Fabio's
>>> proposed change.
>>> >
>>> > I went and looked at the ANSI standard (draft), btw
>>> [1].
>>> >
>>> > There, #xor: is specified as taking only a boolean.
>>> >
>>> > So this would be an extension, potentially affecting
>>> portability, for
>>> > what that's worth these days.
>>> >
>>> > I think the performance objection has been
>>> well-refuted, and I see the
>>> > consistency benefit as being real, but probably
>>> pretty limited, and I
>>> > kind of don't like the potential portability
>>> implications.
>>>
>>> I presume the main "feeling" here is parallelity:
>>>
>>> #& takes an evaluated boolean #and: takes an
>>> unevaluated block
>>> #| takes an evaluated boolean #or: takes an
>>> unevaluated block
>>>
>>> #xor: takes an evaluated boolean but looks like #and:
>>> and #or:,
>>> So it seems to belong to the right side, and then we
>>> think again about
>>> the left side, come up with symbols, only to find that
>>> #~= and #~~ are already there.
>>>
>>> So, just lets go all the way and document #xor:
>>> better, not making take it a block,
>>> maybe pointing out that #~= ist typically better
>>> fitted…
>>>
>>> Best regards
>>> -Tobias
>>>
>>>
>>> So, I have written some tests for speed and 'ensuring the
>>> arguments are booleans', with another proposed solution.
>>>
>>> First, speed:
>>>
>>> #xor: base
>>> #~= is 124% slower (or 2-1/4 as much time as existing xor:
>>> method)
>>> #~~ is 75% faster
>>> #cbcXor: is 32% slower
>>>
>>> Note: for real speed, use ~~ , not ~= !
>>>
>>> Why cbcXor: ? It is the only one that makes sure the
>>> arguments are boolean - fails otherwise.
>>>
>>>
>>> Here is a simpler and faster alternative:
>>>
>>> True >> #xor: aBoolean
>>>
>>> aBoolean ifTrue: [ ^false ] ifFalse: [ ^true ]
>>>
>>> False >> #xor: aBoolean
>>>
>>> aBoolean ifTrue: [ ^true ] ifFalse: [ ^false ]
>>>
>>>
>>> and is this noticeably slower?
>>>
>>> True >> #xor: aBoolean
>>>
>>> ^aBoolean ifTrue: [ false ] ifFalse: [ true ]
>>>
>>> False >> #xor: aBoolean
>>>
>>> ^aBoolean ifTrue: [ true ] ifFalse: [ false ]
>>>
>>
>> Yes, it is. Here are the bytecodes for your suggestion:
>>
>> 33 <10> pushTemp: 0
>> 34 <99> jumpFalse: 37
>> 35 <71> pushConstant: true
>> 36 <90> jumpTo: 38
>> 37 <72> pushConstant: false
>> 38 <7C> returnTop
>>
>> And for my variant:
>>
>> 33 <10> pushTemp: 0
>> 34 <98> jumpFalse: 36
>> 35 <79> return: true
>> 36 <7A> return: false
>>
>> I measured the latter to be 14% faster.
>
>
> For xor: it's hardly worth it. Nicer if the compiler and decompiler did
> the transformation...
>
>
>>
>>
>> Levente
>>
>>
>>
>>> but I would much prefer to see either
>>>
>>> Boolean>>xor: aBooleanOrBlock
>>>
>>> ^ aBooleanOrBlock value not
>>>
>>> or
>>>
>>> True >> #xor: aBooleanOrBlock
>>>
>>> ^aBooleanOrBlock value ifTrue: [ false ] ifFalse: [ true ]
>>>
>>> False >> #xor: aBooleanOrBlock
>>>
>>> ^aBooleanOrBlock value ifTrue: [ true ] ifFalse: [ false ]
>>>
>>> The lack of symmetry with and: and or: is, IMO, bad.
>>>
>>>
>>> Levente
>>>
>>>
>>> Tests to run:
>>>
>>> First, install
>>>
>>> True>>cbcXor: boolean
>>> ^boolean isFalse
>>> True>>isTrue
>>> ^true
>>> True>>isFalse
>>> ^false
>>> False>>cbcXor: boolean
>>> ^boolean isTrue
>>> False>>isFalse
>>> ^true
>>> False>>isTrue
>>> ^false
>>>
>>> "Setup"
>>> pairs := #( true false true true false false false true ).
>>> invalidPairs := { true. 1. true. #[ 1 3 0 9 ]. true. 'abc'.
>>> false. 1. false. #[ 1 3 0 9 ]. false. 'abc'. 'abc'. true. #[ 1 3 0 9 ].
>>> false. }.
>>> methods := {
>>> [:f :s| ].
>>> [:f :s| f xor: s].
>>> [:f :s| f cbcXor: s].
>>> [:f :s| f ~= s].
>>> [:f :s| f ~~ s].
>>> }.
>>> "Validity Test"
>>> validCheck := methods collect: [:m|
>>> {
>>> m sourceString.
>>> #( true false false true ) = (pairs pairsCollect: [:a :b| [m
>>> value: a value: b] on: Error do: [#error]])
>>> ifTrue: ['Valid'] ifFalse: ['ERRORS'].
>>> pairs pairsCollect: [:a :b| [m value: a value: b] on: Error
>>> do: [#error]].
>>> }].
>>> "all methods are valid"
>>> "Testing that non-booleans actually result in errors, and
>>> not false positive/negatives"
>>> invalidCheck := methods collect: [:m|
>>> {
>>> m sourceString.
>>> ((invalidPairs pairsCollect: [:a :b| [m value: a value: b]
>>> on: Error do: [#error]]) select: [:r| r = #error]) size = 8
>>> ifTrue: ['Valid'] ifFalse: ['ERRORS'].
>>> invalidPairs pairsCollect: [:a :b| [m value: a value: b] on:
>>> Error do: [#error]].
>>> }].
>>> "Only #cbcXor: correctly fails all of these. Some
>>> interesting results..."
>>> "Timing test. Need to run 10,000,000 to get reasonable
>>> distinctions on my machine."
>>> timing := methods collect: [:m|
>>> { m sourceString. [[10000000 timesRepeat: [pairs pairsDo:
>>> m]] timeToRun] on: Error do: [#invalid]. }
>>> ].
>>> "And showing percentage slower"
>>> base := timing first second.
>>> bench := timing second second - base.
>>> timing allButFirst collect: [:res| { res first. this := res
>>> second - base. ((this - bench) * 100 / bench) rounded. }].
>>>
>>> Thanks,
>>> cbc
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> --
>>> _,,,^..^,,,_
>>> best, Eliot
>>>
>>>
>>
>>
>>
>
>
> --
> _,,,^..^,,,_
> best, Eliot
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20180321/be361631/attachment.html>
More information about the Squeak-dev
mailing list
|