[plt-dev] Re: Speed up check-syntax

From: Eli Barzilay (eli at barzilay.org)
Date: Mon Nov 9 17:08:57 EST 2009

[Moving to plt-dev.]

On Nov  9, Robby Findler wrote:
> 
> I find such behavior annoying in my OS and expect it would be the
> same in DrScheme. Things will be sluggish while it is loading.
> 
> Nevertheless, I will try this if the parallelism stuff doesn't pan
> out.

1. I find the delay-on-first-syncheck especially annoying in class.  I
   always start a new drscheme at the beginning of the class, which
   means that I'm guaranteed to get the annoying delay.  (And it's a
   classic case of unjustified delay, since drscheme will sit there
   for many minutes doing nothing before I get to use it.)  It's at a
   level where I hesitate to use it -- and on some occasions I
   pre-arrange myself so that I click it while I speak to mask out the
   delay.  (Being able to do such things is something that I had to
   learn as a stutterer...)

2. BTW, the status-line message is not showing at all on linux.  I
   never knew that there was supposed to be such a message.  (I almost
   never run it on my laptop.)

3. IMO, the issue will not be completely resolved with multiple
   cores.  What if my other core is busy doing something else?  What
   about school machines that can be very outdated?  What about IO
   delays, since this does involve mostly IO?

4. The usual way to do these things is to have it loaded when it is
   idle (exactly what Stephen said) -- but then don't just start to
   load it so everything becomes slow, just do that in little
   execution chunks which are done only if the system is still
   otherwise idle.  I think that MzScheme could use some more
   functionality in this area -- a nice feature to have would be a way
   for a thread to change its priority where this can also be a "run
   me only when otherwise idle" (it would be especially nice to have a
   hierarchy of these: "run me when otherwise idle including 1st-level
   idle-priority threads, and give me only 20% running time").

5. Fantasies aside, I think that it is possible to do a reasonable job
   for this given the current tools.  The code below looks to me like
   it should work fine.  It runs a given thunk in the background while
   drscheme is idle, and using little cpu time so there's no alarming
   cpu load.  The returned result is a thunk that returns the computed
   value -- waiting for it (while giving it 100% cpu) if it isn't
   ready yet.

6. To try it, I basically changed "syncheck.ss" with this definition:

     (define get-xref
       (run-lazily (lambda ()
                     (with-handlers ([exn? (lambda (_) #f)])
                       (load-collections-xref)))))

   I've tried it in DrScheme (on my Windows laptop, so the delay is
   more noticeable), and it looks like it works fine.  No need for
   multicore support...

7. Maybe this would be a good addition to `scheme/promise'.



;; Run `thunk' when idle, slicing the time to `slice'-second frames,
;; using only `use' seconds from each frame.  Return a thunk that
;; returns the result of the computation, giving it full cpu if it's not
;; ready yet.
(define (run-lazily thunk #:slice [slice 0.3] #:use [use 0.05])
  (define idle-evt (system-idle-evt))
  (define force-sema (make-semaphore 0))
  (define results #f)
  (define (work)
    (with-handlers ([void (lambda (e) (set! results (cons raise e)))])
      (set! results (cons values (call-with-values thunk list)))))
  (define (start)
    (sync idle-evt)
    (let ([worker (parameterize ([current-thread-group (make-thread-group)])
                    (thread work))])
      (thread-suspend worker)
      (let loop ()
        ;; rest, then wait for idle time, then resume working
        (if (eq? (begin0 (or (sync/timeout (- slice use) force-sema)
                             (sync idle-evt force-sema))
                   (thread-resume worker))
                 force-sema)
          ;; forced during one of these => let it run to completion
          (thread-wait worker)
          ;; not forced
          (unless (sync/timeout use worker) (thread-suspend worker) (loop))))))
  (define main-thread
    (parameterize ([current-thread-group (make-thread-group)])
      (thread start)))
  (lambda ()
    (unless (thread-dead? main-thread)
      (semaphore-post force-sema)
      (thread-wait main-thread))
    (apply (car results) (cdr results))))

-- 
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!


Posted on the dev mailing list.