Discussion:
Time to sleep under different platforms
(too old to reply)
Bruno Emond
2010-07-21 17:50:10 UTC
Permalink
I tested the accuracy of the sleep function under different conditions (see the table below).

The table was generated using a very simple function, taking the elapsed time for comparing performance.
I could have done some sampling but these one run results are quite consistent over many repetitions.

The function I used is the following, called form the listener on a freshly launched LW:

(dolist (sec '(1 0.5 0.1 0.05 0.01 0.005 0.001)) (time (sleep sec)))

It is a known fact that Windows XP cannot give accurate time measurement under about 15 msec. This problem is apparently solved in Vista.

Notice that I also ran a test with a Vista virtual image on a MacPro with excellent accuracy (within 1msec).

Does anyone know of a Lisp solution to give Windows XP a better time resolution?

Thanks for your replies.

Bruno

Machine OS LW (Sleep x)
1.000 0.500 0.100 0.050 0.010 0.005 0.001
MacPro MacOS X 10.4.6 6.0 64bit 1.001 0.500 0.100 0.050 0.010 0.005 0.002
Vista Business 6.0 32bit 1.001 0.501 0.101 0.051 0.010 0.006 0.002
DELL - Latitude|E6500 XP 32 5.1 32bit 1.016 0.516 0.109 0.063 0.015 0.016 0.016
DELL - Precision|M6400 XP 64 6.0 32bit 1.000 0.500 0.110 0.062 0.016 0.015 0.016
Denis Pousseur
2010-07-21 19:46:43 UTC
Permalink
It's strange that sleep is much more accurate than the functions of the mp
package
With an intel mac :

Compute the number of ticks in one second :

(loop with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
while (< time end)
do (sleep 0.001)
count time)

=> 500 (which confirm perfectly your observation : on mac the better
resolution - with sleep - is 2ms) and sleep gives a nive regularity as show
this other test :

Compute the min, max and average interval between ticks :

(loop with prev
with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
for interval = (and prev (- time prev))
for i from 0
while (< time end)
do (sleep 0.001)
when interval collect interval
and maximize interval into max
and minimize interval into min
and sum interval into mean
do (setf prev time)
finally (return (list min max (float (/ mean i))))) => (2 3 2.0040162)

The same with (mp:process-wait-with-timeout "" 0.001) in place of sleep :

Number of ticks => around 110
Min and max interval => (1 12 8.910714)

MP seems to be limited to a 10 ms precision (but less regular than sleep)

In the other side, using some low level procedure of the mac, I can obtain a
1 ms resolution and even better. So the OS is not all. Many programs which
need a high level of time precision run very well on XP. Don't you think
that you can obtain a better resolution by using some specific OS
functionalities ?

Best regards

Denis
Post by Bruno Emond
I tested the accuracy of the sleep function under different conditions (see
the table below).
The table was generated using a very simple function, taking the elapsed time
for comparing performance.
I could have done some sampling but these one run results are quite consistent
over many repetitions.
(dolist (sec '(1 0.5 0.1 0.05 0.01 0.005 0.001)) (time (sleep sec)))
It is a known fact that Windows XP cannot give accurate time measurement under
about 15 msec. This problem is apparently solved in Vista.
Notice that I also ran a test with a Vista virtual image on a MacPro with
excellent accuracy (within 1msec).
Does anyone know of a Lisp solution to give Windows XP a better time resolution?
Thanks for your replies.
Bruno
Machine OS LW
(Sleep x)
1.000 0.500 0.100
0.050 0.010 0.005 0.001
MacPro MacOS X 10.4.6 6.0 64bit 1.001 0.500 0.100
0.050 0.010 0.005 0.002
Vista Business 6.0 32bit 1.001 0.501 0.101
0.051 0.010 0.006 0.002
DELL - Latitude|E6500 XP 32 5.1 32bit 1.016 0.516 0.109
0.063 0.015 0.016 0.016
DELL - Precision|M6400 XP 64 6.0 32bit 1.000 0.500 0.110
0.062 0.016 0.015 0.016
-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail : ***@gmail.com
-------------------------------------------------------
Yuri Davidovsky
2010-07-21 20:00:38 UTC
Permalink
On Wed, 21 Jul 2010 20:46:43 +0100, Denis Pousseur
Post by Denis Pousseur
(loop with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
while (< time end)
do (sleep 0.001)
count time)
This yielded 998 in W7 64.
Post by Denis Pousseur
(loop with prev
with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
for interval = (and prev (- time prev))
for i from 0
while (< time end)
do (sleep 0.001)
when interval collect interval
and maximize interval into max
and minimize interval into min
and sum interval into mean
do (setf prev time)
finally (return (list min max (float (/ mean i)))))
That evaluated to (1 3 1.0070565).
(1 3 1.0060423) with the max going into 5 at most.

BTW, interesting style of LOOPing.
Bruno Emond
2010-07-21 21:34:41 UTC
Permalink
Thanks Denis,

very interesting loops!
That alone was worth my posting.
Post by Denis Pousseur
(loop with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
while (< time end)
do (sleep 0.001)
count time)
=> 500 (which confirm perfectly your observation : on mac the better
resolution - with sleep - is 2ms) and sleep gives a nive regularity as show
Gives me 964. As I said in my original message I only ran the function once. I was not making a claim that the precision on my MacPro (2 X 3 GHz Quad-Core Intel Xeon) was 2 msec.
Yuri seems to have the fastest machine on W7 64 with 998.
In my virtual Vista image the result is 512.
Post by Denis Pousseur
(loop with prev
with end = (+ 1000 (get-internal-real-time))
for time = (get-internal-real-time)
for interval = (and prev (- time prev))
for i from 0
while (< time end)
do (sleep 0.001)
when interval collect interval
and maximize interval into max
and minimize interval into min
and sum interval into mean
do (setf prev time)
finally (return (list min max (float (/ mean i))))) => (2 3 2.0040162)
Result is (1 2 1.0560254) .
Less variability (did not get 3) than Yuri's machine but not as precise (1 3 1.0070565).
In my virtual Vista image the result is (1 3 1.9607073)
Result is (0 2 1.0449791)
Same observations as before. The questionable value is the zero minimum. This would confirm the lack of precision of mp:process-wait-with-timeout because in at least in one instance, it did not wait for 1 msec.
In my virtual Vista image the result is (1 9 1.9762377). Ouch, 9 as a maximum.
Post by Denis Pousseur
In the other side, using some low level procedure of the mac, I can obtain a
1 ms resolution and even better. So the OS is not all. Many programs which
need a high level of time precision run very well on XP. Don't you think
that you can obtain a better resolution by using some specific OS
functionalities ?
Yes using some OS specific functionality (MacOS or Windows) is certainly the way to proceed to obtain the maximum precision.
Post by Denis Pousseur
Post by Bruno Emond
I tested the accuracy of the sleep function under different conditions (see
the table below).
The table was generated using a very simple function, taking the elapsed time
for comparing performance.
I could have done some sampling but these one run results are quite consistent
over many repetitions.
(dolist (sec '(1 0.5 0.1 0.05 0.01 0.005 0.001)) (time (sleep sec)))
It is a known fact that Windows XP cannot give accurate time measurement under
about 15 msec. This problem is apparently solved in Vista.
Notice that I also ran a test with a Vista virtual image on a MacPro with
excellent accuracy (within 1msec).
Does anyone know of a Lisp solution to give Windows XP a better time resolution?
Thanks for your replies.
Bruno
Machine OS LW
(Sleep x)
1.000 0.500 0.100
0.050 0.010 0.005 0.001
MacPro MacOS X 10.4.6 6.0 64bit 1.001 0.500 0.100
0.050 0.010 0.005 0.002
Vista Business 6.0 32bit 1.001 0.501 0.101
0.051 0.010 0.006 0.002
DELL - Latitude|E6500 XP 32 5.1 32bit 1.016 0.516 0.109
0.063 0.015 0.016 0.016
DELL - Precision|M6400 XP 64 6.0 32bit 1.000 0.500 0.110
0.062 0.016 0.015 0.016
-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique
Tel : 32 (0)2 219 31 09
-------------------------------------------------------
Raffael Cavallaro
2010-07-21 23:56:17 UTC
Permalink
Isn't this what cl::internal-time-units-per-second is for?

warmest regards,

Ralph


Raffael Cavallaro
***@me.com
Denis Pousseur
2010-07-22 11:53:46 UTC
Permalink
On my system cl::internal-time-units-per-second return 1000 (and I suppose
on every systems running lw). The result of the test is 500, so it's not the
same thing. But you're right, it's certainly much precise to say : this test
compute the EFFECTIVE number of ticks per second.

Best regards

Denis
Post by Raffael Cavallaro
Isn't this what cl::internal-time-units-per-second is for?
warmest regards,
Ralph
Raffael Cavallaro
-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail : ***@gmail.com
-------------------------------------------------------
Raffael Cavallaro
2010-07-22 14:43:28 UTC
Permalink
Post by Denis Pousseur
On my system cl::internal-time-units-per-second return 1000 (and I suppose
on every systems running lw). The result of the test is 500, so it's not the
same thing. But you're right, it's certainly much precise to say : this test
compute the EFFECTIVE number of ticks per second.
What you're measuring here is the overhead of doing all of these things every time though the loop
1. the loop counter increment
2. get-internal-real-time
3. the comparison with the start time
4. the call to sleep

these things do take some finite time to execute. The counter increment and some sort of comparison are unavoidable - we can't have a finite loop without them, and the calls to sleep are precisely what we want to time. However, if you want to see how far off internal-time-units-per second is wrt sleep, you shouldn't also be doing a call to get-internal-real-time every pass though the loop, and to be precise, we should back out the time for an empty loop of the same size. As it turns out, the empty loop time is negligible (< 1 millisecond), so we can ignore it.

so:

(defun dotimes-ticktest (&optional (times 1000))
(declare (optimize (speed 3) (safety 0) (debug 0) (compilation-speed 0)
(space 0) (fixnum-safety 0) (float 0)))
(let* ((sleeptime (float (/ internal-time-units-per-second) 0.0s0))
(start (get-internal-real-time))
(stop
(mp:with-interrupts-blocked
(dotimes (n times (get-internal-real-time))
(declare (fixnum n))
(sleep sleeptime)))))
(declare (fixnum start stop) (single-float sleeptime))
(float (/ (- stop start) times))))

on my machine this returns 1.11, or an 11% overhead for the calls to sleep. I get similar results with Clozure Common Lisp and sbcl btw - both show about 10-11% overhead for a large number of calls to sleep.

warmest regards,

Ralph




Raffael Cavallaro
***@me.com
Denis Pousseur
2010-07-22 16:48:05 UTC
Permalink
You're perfectly right. My goal was not to develop a tool to measure the
sleep performances. Just to speak about the difference between sleep and the
mp package functions. I suppose that the difference observed with this loop
are not contradicted by your test (at least if we speak of practical
situations and not of pure theory).

Naturally a scheduler cannot be based on a loop like this one, as you said
the time for operations must be included. Moreover, it is why it's not
possible to have a ms scheduler on pure lisp, even with sleep, because to
have one wee need a smaller time definition than ms. The procedure I use on
mac is based on machine time at a resolution of 1.000.000 per second on an
intel mac (less on power pc). With this resolution it's possible to include
the time of the tasks in the computation and have, globally, an ms
resolution (the wait function is not based on an interval but on a point to
reach always relative to the start point).

This message was also to said that something similar is certainly possible
on XP, otherwise I really don't know how some software I used on XP
(especially for sound edition) could works at a 88khz definition...

Anyway, thanks for your very interesting demonstration !

Best regards

Denis
Post by Raffael Cavallaro
Post by Denis Pousseur
On my system cl::internal-time-units-per-second return 1000 (and I suppose
on every systems running lw). The result of the test is 500, so it's not the
same thing. But you're right, it's certainly much precise to say : this test
compute the EFFECTIVE number of ticks per second.
What you're measuring here is the overhead of doing all of these things every
time though the loop
1. the loop counter increment
2. get-internal-real-time
3. the comparison with the start time
4. the call to sleep
these things do take some finite time to execute. The counter increment and
some sort of comparison are unavoidable - we can't have a finite loop without
them, and the calls to sleep are precisely what we want to time. However, if
you want to see how far off internal-time-units-per second is wrt sleep, you
shouldn't also be doing a call to get-internal-real-time every pass though the
loop, and to be precise, we should back out the time for an empty loop of the
same size. As it turns out, the empty loop time is negligible (< 1
millisecond), so we can ignore it.
(defun dotimes-ticktest (&optional (times 1000))
(declare (optimize (speed 3) (safety 0) (debug 0) (compilation-speed 0)
(space 0) (fixnum-safety 0) (float 0)))
(let* ((sleeptime (float (/ internal-time-units-per-second) 0.0s0))
(start (get-internal-real-time))
(stop
(mp:with-interrupts-blocked
(dotimes (n times (get-internal-real-time))
(declare (fixnum n))
(sleep sleeptime)))))
(declare (fixnum start stop) (single-float sleeptime))
(float (/ (- stop start) times))))
on my machine this returns 1.11, or an 11% overhead for the calls to sleep. I
get similar results with Clozure Common Lisp and sbcl btw - both show about
10-11% overhead for a large number of calls to sleep.
warmest regards,
Ralph
Raffael Cavallaro
-------------------------------------------------------
Denis Pousseur
70 rue de Wansijn
1180 Bruxelles, Belgique

Tel : 32 (0)2 219 31 09
Mail : ***@gmail.com
-------------------------------------------------------
Yuri Davidovsky
2010-07-24 21:14:40 UTC
Permalink
On Thu, 22 Jul 2010 17:48:05 +0100, Denis Pousseur
Post by Denis Pousseur
otherwise I really don't know how some software I used on XP
(especially for sound edition) could works at a 88khz definition...
Well, for sound processing 50 frames per second is fairly acceptable, that
amounts to 20 ms buffers, which is manageable even with interpreted code,
as the examples have shown.

Michael Lenaghan
2010-07-21 20:07:28 UTC
Permalink
Post by Bruno Emond
It is a known fact that Windows XP cannot give accurate time measurement
under about 15 msec. This problem is apparently solved in Vista.
How To Use QueryPerformanceCounter to Time Code

http://support.microsoft.com/kb/172338
Loading...