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

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Mon Nov 9 17:15:07 EST 2009

PS: feel free to check this in, but it probably belongs in
scribble/xref or setup/xref, not in the syntax checker.


On Mon, Nov 9, 2009 at 4:13 PM, Robby Findler
<robby at eecs.northwestern.edu> wrote:
> Thanks, Eli. That looks nice.
> Matthew suggested something similar, but using mzlib/couroutine, where
> I use a low-priority gui callback to give the thread the next quantum.
> Robby
> On Mon, Nov 9, 2009 at 4:08 PM, Eli Barzilay <eli at barzilay.org> wrote:
>> [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.