This is great Eliot. Thank you and 3DICC.�� After loading the changeset
On Fri, Jan 8, 2016 at 1:20 AM, Eliot Miranda <eliot.miranda@gmail.com> wrote:
>
> and here's a version with a better class comment
>
> On Thu, Jan 7, 2016 at 9:12 AM, Eliot Miranda <eliot.miranda@gmail.com> wrote:
>>
>> Hi Denis, Hi Cl��ment,�� Hi Frank,
>>
>> On Thu, Jan 7, 2016 at 5:34 AM, Cl��ment Bera <bera.clement@gmail.com> wrote:
>>>
>>> Hello,
>>>
>>> Eliot, please, you told me you had the code and Denis is interested.
>>>
>>> It uses 3 primitives for performance.
>>
>>
>> Forgive the delay.�� I thought it proper to ask permission since the code was written while I was at Qwaq. I'm attaching the code in a fairly raw state, see the attached.�� The code is MIT, but copyright 3DICC.
>>
>> It is a plugin replacement for Squeak's Mutex, and with a little ingenuity could be a replacement for Squeak's Monitor.�� It is quicker because it uses three new primitives to manage entering a critical section and setting the owner, exiting the critical section and releasing the owner, and testing if a critical section, entering if the section is unowned.�� The use of the primitives means fewer block activations and ensure: blocks in entering and exiting the critical section, and that's the actual cause of the speed-up.
>>
>> You can benchmark the code as is.�� Here are some results on 32-bit Spur, on my 2.2GHz Core i7
>>
>> {Mutex new. Monitor new. CriticalSection new} collect:
>> [:cs| | n |
>> n := 0.
>> [cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1].
>> cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1].
>> n ] bench]
>>
>> {Mutex new. Monitor new. CriticalSection new} collect:
>> [:cs| | n |
>> n := 0.
>> cs class name, ' -> ',
>> [cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1]. cs critical: [n := n + 1].
>> cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1]. cs critical: [n := n - 1].
>> n ] bench]
>>
>> #( 'Mutex -> 440,000 per second. 2.27 microseconds per run.'
>> 'Monitor -> 688,000 per second. 1.45 microseconds per run.'
>> 'CriticalSection -> 1,110,000 per second. 900 nanoseconds per run.')
>>
into Pharo-50515 (32 bit Spur) I get the following results on my
laptop i5-2520M @ 2.50GHz
#('Mutex -> 254,047 per second'
��'Monitor -> 450,442 per second'
��'CriticalSection -> 683,393 per second')
In a fresh Image "Mutex allInstances basicInspect" lists just two mutexes...
1. NetNameResolver-->ResolverMutex
2. ThreadSafeTranscript-->accessSemaphore
cheers -ben
>> Replacement is probably trivial; rename Mutex to OldMutex, rename CriticalSection to Mutex, recompile.�� But there are lots of mutexes in the system and these are potentially owned.�� Transforming unowned ones is trivial, but transforming owned ones is, I think, impossible.�� But at least in my system there are no owned mutexes or monitors.
>>
>> Frank (or anyone else), would you be interested in creating a replacement for Squeak's Monitor based on CriticalSection?
>>
>>
>> Here are the two business methods:
>> CriticalSection methods for mutual exclusion
>> critical: aBlock
>> "Evaluate aBlock protected by the receiver."
>> ^self primitiveEnterCriticalSection
>> ifTrue: [aBlock value]
>> ifFalse: [aBlock ensure: [self primitiveExitCriticalSection]]
>>
>> critical: aBlock ifLocked: lockedBlock
>> "Answer the evaluation of aBlock protected by the receiver.�� If it is already in a critical
>> section on behalf of some other process answer the evaluation of lockedBlock."
>> ^self primitiveTestAndSetOwnershipOfCriticalSection
>> ifNil: [lockedBlock value]
>> ifNotNil:[:alreadyOwner|
>> alreadyOwner
>> ifTrue: [aBlock value]
>> ifFalse: [aBlock ensure: [self primitiveExitCriticalSection]]]
>>
>> and the primitives:
>> CriticalSection methods for private-primitives
>> primitiveEnterCriticalSection
>> "Primitive. The receiver must be unowned or owned by the current process to proceed.
>> Answer if the process is owned by the current process."
>> <primitive: 186>
>> self primitiveFailed
>> "In the spirit of the following"
>> "[owner ifNil:
>> [owner := Processor activeProcess.
>> ^false].
>>�� owner = Processor activeProcess ifTrue:
>> [^true].
>>�� self addLast: Processor activeProcess.
>>�� Processor activeProcess suspend] valueUnpreemptively"
>>
>> primitiveExitCriticalSection
>> "Primitive. Set te receiver to unowned and if any processes are waiting on
>> the receiver then proceed the first one, indicating that the receiver is unowned."
>> <primitive: 185>
>> self primitiveFailed
>> "In the spirit of the following"
>> "[owner := nil.
>>�� self isEmpty ifFalse:
>> [process := self removeFirst.
>> process resume]] valueUnpreemptively"
>>
>> primitiveTestAndSetOwnershipOfCriticalSection
>> "Primitive. Attempt to set the ownership of the receiver.
>> If the receiver is unowned set its owningProcess to the
>> activeProcess and answer false.�� If the receiver is owned
>> by the activeProcess answer true.�� If the receiver is owned
>> by some other process answer nil."
>> <primitive: 187>
>> self primitiveFail
>> "In the spirit of the following"
>> "[owner ifNil:
>> [owningProcess := Processor activeProcess.
>> ^false].
>>�� owner = Processor activeProcess ifTrue: [^true].
>>�� ^nil] valueUnpreemptively"
>>
>>> 2016-01-07 13:24 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
>>>>
>>>>
>>>> Hello.
>>>>
>>>> I hear about new Monitor implementation based on new primitives.
>>>> Where to get it?
>>
>>
>> _,,,^..^,,,_
>> best, Eliot
>
>
>
>
> --
> _,,,^..^,,,_
> best, Eliot
>