[Vm-dev] Delays should wakeup the idle process (patch)

John McIntosh johnmci at smalltalkconsulting.com
Fri Jul 15 23:07:13 UTC 2011

Ok, so after fiddling with this for the last decade let me had over
some words of advice

(a)  the relinquishPhysicalProcessor (whatever it's called) is passed
a value, this value is bogus magic meaningless number
(b) I did attempt to get that number from the Delay logic, but mmm
good luck, the last attempt killed images because it would deadlock on
a mutex semaphore lurking in Delay
(c) That led to the realization you could ask for vm->getNextWakeup()
tick which might be zero some day.
(d) getNextWakeup() might be now() or near now()  and sleeping might
be a bad idea
(e) getNextWakeup() might be now() or in the near past yet we might
get called another 8 times before the smalltalk process lurch awake
(no idea why that is observed).
(f)  Anyway you have some reflect of sleep time once you decide how
large that value has to be.
(g) Isn't it one CPU one process why sleep?
(h) The pthread_cond_timedwait (yes I did that years back) won't fly
because you miss the interrupt from socket/files/UI which leaves to
the odd behavior if squeak is busy good web server, if squeak is idle
the bad web server...   "it always sends at 50 packets per second "

Therefore to sleep you have to use some OS call that let's you sleep
but wake up early when work needs to be done.
So to help befuddle your operating systems come with a variety of
system calls that actually might or might not work.
Off then to consider aioSleep() which does this dance with aioPoll ()
which *cough* has different behaviour if or if there is any file
descriptors open. Oddly an iphone app might not have any open for your
image lacking changeset and no sockets open...

Anyway nanosleep is used as that promises to be more accurate. Then if
it terminates early (don't bother checking) we run the aioPoll.
If of course nanosleep is defective or non-existant, then we ask
aioPoll to do the wait, but that usually has even worse behaviour.
Anyway after nanosleep wakes do the dance and service those sockets
and file descriptors.

On Fri, Jul 15, 2011 at 10:15 AM, John M McIntosh
<johnmci at smalltalkconsulting.com> wrote:
> I'll see if can gather some historical thoughts on this later today
> Sent from my iPhone
> On 2011-07-15, at 7:47 AM, Juan Vuletich <juan at jvuletich.org> wrote:
>> Bert Freudenberg wrote:
>>> On 15.07.2011, at 01:40, Matthew Fulmer wrote:
>>>> On my unix vm, Delay wakeups often happen a lot later than requested
>>>> if the idle process kicks in. Craig provided a bit of code from spoon
>>>> that fixes this issue:
>>>> http://bugs.squeak.org/view.php?id=7652
>>> Very interesting.
>>> On John's 4.x Mac VM I get 990 wakeups/sec.
>>> Same for John's 5.7.4, 990/s.
>>> But 5.8, and recent Cog/Stack VMs only do < 500 wakeups/sec. Both Carbon and Cocoa versions.
>>> - Bert -
>> Right. Strangely, on recent Mac VMs, the behavior is not affected by idle process / relinquish primitive. I turned Matthew's snippet into the attached test. Another strange thing is that (on a recent Mac VM) this test fails for 1mS and 5 mS, but passes for 2mS!
>> HTH.
>> Cheers,
>> Juan Vuletich
>> 'From Cuis 3.3 of 2 June 2011 [latest update: #1024] on 15 July 2011 at 8:28:03 am'!
>> !classDefinition: #RelinquishPrimitiveTest category: #'Kernel-Tests'!
>> TestCase subclass: #RelinquishPrimitiveTest
>>    instanceVariableNames: ''
>>    classVariableNames: ''
>>    poolDictionaries: ''
>>    category: 'Kernel-Tests'!
>> !RelinquishPrimitiveTest methodsFor: 'testing' stamp: 'jmv 7/15/2011 08:25'!
>> testDelayAccuracy
>>    "
>>    RelinquishPrimitiveTest new testDelayAccuracy
>>    Test void relinquishPhysicalProcessor(void); in the VM.
>>    See http://bugs.squeak.org/view.php?id=7652
>>    See http://permalink.gmane.org/gmane.comp.lang.smalltalk.squeak.vm.devel/6381
>>    It appears that for some VMs, the relinquish primitiva takes too long to return?
>>    This should print a number close to 1000
>>    | tally delay morph updateDelay |
>>    tally := 0. delay := Delay forMilliseconds: 1.
>>    updateDelay := Delay forMilliseconds: 1000.
>>    morph := StringMorph new openInWorld.
>>    [[tally := tally + 1. delay wait] repeat] forkAt: 44.
>>    [[morph contents: tally printString. tally := 0. updateDelay wait] repeat] forkAt: 45.
>>    Evaluating this avoids the iddle process, and in some VMs (Linux) it seems to make the tally go from almost 500 to almost 1000.
>>    This trick doesn't seem to work on recent Mac VMs (the 4.2.4 Mac VM is always close 1000), as it is always a bit below 500
>>    [[] repeat] forkAt: 35
>>    "
>>    self testDelayAccuracy: 10.
>>    self testDelayAccuracy: 6.
>>    self testDelayAccuracy: 5.
>>    self testDelayAccuracy: 2.
>>    self testDelayAccuracy: 1! !
>> !RelinquishPrimitiveTest methodsFor: 'testing' stamp: 'jmv 7/15/2011 08:27'!
>> testDelayAccuracy: delayTime
>>    "
>>    RelinquishPrimitiveTest new testDelayAccuracy
>>    See comment there.
>>    "
>>    | tally delay updateDelay counter |
>>    tally _ 0.
>>    delay _ Delay forMilliseconds: delayTime.
>>    updateDelay _ Delay forMilliseconds: 1000.
>>    counter _ [[tally _ tally + 1. delay wait] repeat] newProcess.
>>    counter resumeAt: 44.
>>    tally _ 0.
>>    updateDelay wait.
>>    counter terminate.
>>    self assert: tally > (900/delayTime) description: 'Delay accuracy. Observed: ',
>>        (1000.0 / tally roundTo: 0.01) printString, ' mS. Requested: ', delayTime asFloat printString, ' mS.'! !

John M. McIntosh <johnmci at smalltalkconsulting.com>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com

More information about the Vm-dev mailing list