[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Millisecond Timing in MACL...



   Date: Mon, 18 Feb 91 11:12:38 -0500
   From: Andrew L. M. Shalit <alms>
   To: waander@cs.UMD.EDU
   Cc: info-macl
   Subject: Millisecond Timing in MACL...
   
   
      Date: Sun, 17 Feb 91 23:21:07 -0500
      From: waander@cs.UMD.EDU (Bill Andersen)
   
   
        Is there an easy way to bypass the event handling mechanism in MACL 
      for getting responses from a user?  I'm writing some code to perform
      psychology experiments and the 1 tick (16.67 ms) granularity of the
      event system is not going to do the trick.  Please, someone save me
      from having to do some real C hacking or (God help me) assembler!!!
   
        I want to monitor both mouse clicks and keyboard responses.  Thanks
      in advance...
   
        ...Bill Andersen
        waander@cs.umd.edu
   
   What makes you think the event system has a 1 tick granularity?
   Granted, that's the fastest rate at which EVENT-DISPATCH will
   automatically be called by the MACL preemption mechanism.  But,
   your program is free to sit in a loop and call EVENT-DISPATCH as
   frequently as it likes.
   
Yes, you can do event processing more often than every 1/60 second.
This won't help you measure the elapsed time with more precision,
which I assume is what you want.  It is possible to use the time
manager to measure elapsed time completely in Lisp code.  You'll
probably want to insert an *EVENTHOOK* that catches mouse down and/or
key down events and tells your timing code that the desired event
happenned.  For more precision (EVENT-DISPATCH lets other applications
run under MultiFinder), you'll want to use the _BUTTON trap to check
for the mouse button pushed, and the _GetKeys trap to check for key
transitions.  Here's an example use of _GetKeys:

(defun key-down-p (key-code)
  (multiple-value-bind (byte bit) (floor key-code 8)
    (%stack-block ((p #.(/ 128 8)))
      (_GetKeys :ptr p)
      (logbitp bit (%get-byte p byte)))))

And here's some code showing how to use the time manager (it assumes
existence of the Revised Time Manager which made it's appearance in
Macintosh System 6.0.3):

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; time-code.lisp
;
; Example of using the time manager to measure elapsed times from Lisp
; (TIME-CODE VAR . BODY)
; will execute BODY and setq VAR to the number of elapsed microseconds
; as a side-affect.  The maximum time that can be measured is about 20 minutes.
; This version doesn't account for the time required do the timing, nor
; does it run WITHOUT-INTERRUPTS.

(in-package :ccl)

(export 'time-code :ccl)

(eval-when (eval compile)
  (require :traps))

(defrecord TMTask 
   (qLink :pointer)
   (qType :integer)
   (tmAddr :pointer)
   (tmCount :longint)
   (tmWakeUp :longint)
   (tmReserved :longint)
   )

; Negative time = microseconds
(defconstant *max-time* (- (ash 1 30)))

(defmacro null-ptr ()
  #+ :ccl-1 0
  #+ :ccl-2 `(%null-ptr))

(defmacro time-code (time-var &body body)
  (let ((tmtask (gensym)))
    `(rlet ((,tmtask :tmtask 
                     :qLink (null-ptr)
                     :qType 0
                     :tmAddr (null-ptr)
                     :tmCount 0))
       (_InsTime :errchk :a0 ,tmtask)
       (_PrimeTime :errchk :a0 ,tmtask :d0 *max-time*)
       (unwind-protect
         (progn ,@body)
         (progn
           (_RmvTime :errchk :a0 ,tmtask)
           (setq ,time-var (rref ,tmtask :tmtask.tmCount))
           (setq ,time-var (- ,time-var *max-time*)))))))