Hi Denis, Hi Clément, Hi Frank,
On Thu, Jan 7, 2016 at 5:34 AM, Clément Bera <bera.clement(a)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.')
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(a)gmail.com>:
>
>>
>> Hello.
>>
>> I hear about new Monitor implementation based on new primitives.
>> Where to get it?
>>
>
_,,,^..^,,,_
best, Eliot