SLEEP accuracy

Bug #308950 reported by Nikodemus Siivola
2
Affects Status Importance Assigned to Milestone
SBCL
Won't Fix
Low
Unassigned

Bug Description

  The more interrupts arrive the less accurate SLEEP's timing gets.
    (time (sb-thread:terminate-thread
            (prog1 (sb-thread:make-thread (lambda ()
                                            (loop
                                             (princ #\!)
                                             (force-output)
                                             (sb-ext:gc))))
              (sleep 1))))

Tags: asynch
Changed in sbcl:
importance: Undecided → Medium
status: New → Confirmed
Changed in sbcl:
importance: Medium → Low
Revision history for this message
Gábor Melis (melisgl) wrote :

This is a known problem with nanosleep(2), the manpage on linux describes it in detail. Because of this, clock_nanosleep(2) was born and it should be portable. Now the only issue I see with clock_nanosleep (which applies to nanosleep as well) is that it's not specified to be async signal safe. So either we can live with potential deadlocks if a timer, or interrupt-thread uses sleep or we have to fall back on a select based implementation.

Come to think of it, the deadline mechanism is also affected and since a lot of functions only support timeouts and not deadlines (select(), just to name a showstopper) it's not possible to solve this in general. But is should be possible to fix the async signal safety part by using select() with a timeout.

Changed in sbcl:
assignee: nobody → Nikodemus Siivola (nikodemus)
status: Confirmed → In Progress
Revision history for this message
Nikodemus Siivola (nikodemus) wrote :

Test-case for asynch signal safety of SLEEP:

  (let* ((*level* -1)
         (timer-count 20) ; tuning parameters
         (min-sleep 0.0001)
         (max-sleep 0.001)
         (target 10)
         (nesting-table (make-array 0 :initial-element 0 :adjustable t :fill-pointer 0))
         (firing-table (make-array timer-count :initial-element 0))
         (count 0)
         (make-timekeeper
           (lambda (id)
             (lambda ()
               (let* ((level (1+ *level*))
                      (*level* level))
                 (declare (special *level*))
                 (if (< level (length nesting-table))
                     (incf (aref nesting-table level))
                     (vector-push-extend 1 nesting-table))
                 (incf count)
                 (incf (aref firing-table id))
                 (let ((sec (+ min-sleep (random max-sleep))))
                   (sb-sys:with-interrupts
                     (sleep sec)))))))
         (timers (loop for i from 0 below timer-count
                       collect
                          (sb-ext:make-timer (funcall make-timekeeper i)
                                             :name (format nil "Sleep Timer ~S" i)))))
    (declare (special *level*))
    (sb-sys:without-interrupts
      (dolist (timer timers)
        (sb-ext:schedule-timer timer (+ min-sleep (random max-sleep))
                               :repeat-interval (+ min-sleep (random max-sleep)))))
    (sleep 0.1)
    (sb-sys:without-interrupts
      (loop for nesting = (length nesting-table)
            for mincount = (reduce #'min firing-table)
            until (and (= nesting timer-count) (<= target mincount))
            do (format t "Spinning: Count ~D, Mincount ~D, Nesting ~D~%"
                       count mincount nesting)
               (sb-sys:with-local-interrupts
                 (sleep 0.1))))
    (sb-sys:without-interrupts
      (dolist (timer timers)
        (sb-ext:unschedule-timer timer)))
    (values firing-table nesting-table))

Revision history for this message
Douglas Katzman (dougk) wrote :

terminate-threa = don't use.
GC in a hard loop = not interesting.
make-timer, with-interrupts, without-interrupts = don't care

Changed in sbcl:
assignee: Nikodemus Siivola (nikodemus) → nobody
status: In Progress → Won't Fix
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.