[plt-scheme] High precision timing and MrEd/OSX

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Dec 22 08:16:00 EST 2004

At 22 Dec 2004 21:23:20 +1100, Rohan Drape wrote:
> I will look into your other suggestions in the next weeks, it would be
> nice to implement this all in scheme, with further bonus that then it
> would work under Windows.  If I can get it working I will do some
> measurements and let you know how it compares.

Great - thanks!

To get some idea of the issues involved, I decided to do a quick
experiment myself.

The v299 code below implements a little `set-timer' interface that is
like yours (I think); the timer posts the semaphore `s' when it

On my Linux machine, the displayed time delta is within 30 usec of the
requested 0.1-msec delay.

But there's a catch: I had to throw in a busy loop to ensure that
MzScheme doesn't sleep via select(). Apparently, select() on my OS
times out only on 10-msec boundaries. So, this might be a reason to
keep your timer. Or maybe we should change MzScheme so that it installs
its own timer to get finer-grained sleep times.

(Minor caveat: If I request an alarm from anywhere between 15 and 30
msec, then the actual interval is 30 msec. But if I redirect the
printout to a file, this doesn't happen. So the 15-to-30-msec case is
related to the OS scheduler, which gives MzScheme a 15-msec timeslice
and then switches to the terminal application to show MzScheme's



;; Semaphore that is posted to signal the timeout
(define s (make-semaphore))

;; Channel to communicate to the alarm-server thread
(define req-ch (make-channel))

;; Function to run in the alarm-server thread
(define (serve time-to-post)
  ;; Wait for either the timeout or a new request:
  (sync (handle-evt
	 (alarm-evt time-to-post)
	 (lambda (x)
	   (semaphore-post s)
	   (serve +inf.0)))
	 (lambda (t)
	   (serve (min t time-to-post))))))

;; Start the server thread for set-itimer
(thread (lambda () (serve +inf.0)))

;; Request an alarm at time `time-to-post':
(define (set-itimer time-to-post)
  (channel-put req-ch time-to-post))

;; Busy loop to avoid select()-based sleep. Yuck.
(thread (lambda () (let loop () (sleep) (loop))))

(let loop ()
  (let ([now (current-inexact-milliseconds)])
    ;; Initially, request a semaphore post after 1 msec:
    (set-itimer (+ now 1))
    ;; Change that to 0.1 msec (to test adjusting the alarm):
    (set-itimer (+ now 0.1))
    ;; Wait for the timeout:
    (semaphore-wait s)
    ;; Measure actual delay:
    (printf "~a~n" (- (current-inexact-milliseconds) now))

Posted on the users mailing list.