FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

MATHEMATICS

Measure timing


I have considerable experience with the Time Manager task method of measuring intervals, and recommend strongly against it. To avoid crashes, you need to install the task just once (you seem to be installing it often), and then remove it when you have finished (which you seem not to be doing).

Here is the simplest method I know of for timing things at the microsecond level. This lovely method came originally from (of course) Rick. I have modified and simplified FN Microseconds& from Rick's original; it must now be the shortest LOCAL FN that actually does something useful.
This method has the dual merits of being understandable and not causing crashes if misapplied. The example shows how to measure the overhead of calling FN MicroSeconds& itself (about 20microsec on a 7220/200). There is some "random slop" in individual values returned by FN MicroSeconds& -- about 20 microseconds -- so for reasonable accuracy you should ensure that you ask it to time a substantially greater interval, say 200 microsec minimum. Here we do that by timing repeated calls in a loop

LOCAL FN MicroSeconds&
  ` dc.w $A193
END FN

DIM was&, now&
WINDOW 1
n&=10000
was&=FN MicroSeconds&
'code to be timed
FOR j&=1 TO n&
  FN MicroSeconds& 'just an example, folks! ; put anything here
NEXT j&
'end of code to be timed
now&=FN MicroSeconds&
PRINT (now&-was&)/n& "microseconds per loop"
DO
UNTIL FN BUTTON

Robert Purves


I came up with this and it works well for me...
If msCount& > 0 then the delay is in milliseconds
If msCount& < 0 then the delay is in microseconds
for your case use :
msCount& = -300

This should give you a .3 ms delay

There is obviously some overhead in the function, so the faster the computer the more accurate it would be !!

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

LOCAL MODE
LOCAL FN InsXTime(tmTaskPtr&)
  ` MOVE.L ^tmTaskPtr&,-(SP) ;QElemPtr
  ` DC.W $205F,$A458
END FN

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

LOCAL MODE
LOCAL FN PrimeTime(tmTaskPtr&,count&)
  ` MOVE.L ^tmTaskPtr&,-(SP) ;QElemPtr
  ` MOVE.L ^count&,-(SP) ;LONGINT
  ` DC.W $201F,$205F,$A05A
END FN

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

LOCAL MODE
LOCAL FN RmvTime(tmTaskPtr&)
  ` MOVE.L ^tmTaskPtr&,-(SP) ;QElemPtr
  ` DC.W $205F,$A059
END FN

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

CLEAR LOCAL MODE
LOCAL FN DelayMS(msCount&)
  DIM delayTaskRec.24
  _tmUser = 22
  delayTaskRec.tmAddr& = LINE "DelayTask"
  delayTaskRec.tmCount& = _nil
  delayTaskRec.tmReserved& = _nil
  FN InsXTime(@delayTaskRec)
  FN PrimeTime(@delayTaskRec,msCount&)
  DO
  UNTIL delayTaskRec.tmUser%
  FN RmvTime(@delayTaskRec)
  EXIT FN
"DelayTask"
  ` ADDA.L #tmUser,A1
  ` MOVE.W #1,(A1)
  ` RTS
END FN

'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Bill Sanford


Just to add a little background to Bill's very nice code.

There are three versions of the Time Manager,

The original Time Manager was introduced with the Macintosh Plus ROM (which are also used in Macintosh 512K enhanced models). The smallest time interval delay available is 1 millisecond.

System software version 6.0.3 introduced a revised version of the Time Manager. This version provides better time resolution and more accurate measurements of elapsed time. You can represent time delays in the revised Time Manager as microseconds (msec) as well as milliseconds (msec), with a finest resolution of 20 microseconds.

The extended Time Manager (available with system software version 7.0 and later) contains all the features of earlier Time Managers, with several extensions intended primarily to provide drift-free, fixed-frequency timing services.

As usual you can use gestalt to test for which version of the Time Manager is available.

CONST

gestaltTimeMgrVersion = 'tmgr'; {Time Manager version}

If Gestalt executes successfully, it returns one of three constants:

CONST
gestaltStandardTimeMgr = 1; {original Time Manager}
gestaltRevisedTimeMgr = 2; {revised Time Manager}
gestaltExtendedTimeMgr = 3; {extended Time Manager}

If Gestalt returns an error, you should assume that the original Time Manager is present.

Sean


The following may be what you are after. FN DelayMicroSec had a jitter of only about +/-20 to 40 microseconds on my old Quadra (i.e. for nominal 300 us, range was 320-360 us), but on an iMac the occasional bad long delay occurs (500-600 us). The reason is unclear...

Robert

LONG FN MicroSeconds&
  ` dc.w $A193 ; trap word
END FN ' returns low longword of 8-byte result

LOCAL FN DelayMicroSec(wanTeddelay&)
  waitUntil&=FN MicroSeconds&+wanTeddelay&
  DO
  UNTIL FN MicroSeconds&>=waitUntil&
END FN

DIM elapseTimes&(50)
WINDOW 1
FOR j=1 TO 20 ' test a bunch of nominal 300us delays
  before&= FN MicroSeconds&
  FN DelayMicroSec(300) ' 0.3 ms
  elapseTimes&(j)= FN MicroSeconds&-before&
NEXT j

FOR j=1 TO 20
  PRINT elapseTimes&(j) " microseconds"
NEXT j

DO
UNTIL FN BUTTON


Some time ago this came up and since I have a project (which I may never get around to) which needs millisecond timing I kept the programs. The first program is from Rick Brown. I don't think that it was a private communication. If it was I goofed. The second is a very small snippet of a piece of code from Bill Michael. If you wish more, contact him (or at least get his permission before) I ship it to you.

No. 1 – Rick Brown

COMPILE 0, _caseInsensitive
'---------------------------------
LOCAL FN MicroSeconds(MSecPtr&)
'Call as follows:
' FN MicroSeconds(@theMSec)
'where theMSec is an 8-byte record
  ` dc.w $A193
  ` move.l ^MSecPtr&,a1
  ` move.l a0,(a1)+
  ` move.l d0,(a1)
END FN
'---------------------------------
WINDOW 1
DIM t1.8, t2.8
DEFSTR LONG
INPUT x$

FN MicroSeconds(@t1)
FOR k = 1 TO 10
  FOR i = 1 TO 5000
    FOR j = 1 TO 2037
'Waste a little time...
    NEXT j
  NEXT i
NEXT k

FN MicroSeconds(@t2)
CLS
'Display t1 and t2 in hex:
PRINT "t1: "; HEX$([@t1]);HEX$([@t1+4])
PRINT "t2: "; HEX$([@t2]);HEX$([@t2+4])
'The following calculation serves to find t2 - t1, as long as
'the two times are not separated by more than about 35 minutes:
delta& = [@t2+4] - [@t1+4]
PRINT "t2 - t1 = " USING "##,###,### "; delta& ; "microseconds"
PRINT "t2 - t1 = " USING "##.###,### "; delta& \ 1000000 ; "seconds"
INPUT x$
WINDOW CLOSE(1)
END

Segment 2, Fragment from Bill Michael

CLEAR LOCAL MODE
'To use this procedure you should have a record set up that
'is two longs (record.long1&, record.long2&).
'Pass the pointer to this record in recptr&
LOCAL FN microsecond(recptr&)
  ` MOVE.L ^recptr&, -(sp) 'move recptr& onto stack
  ` DC.W $A193,$225F,$22C8,$2280 'execute the procedure
END FN

CLEAR LOCAL MODE
'this function corrects for FutureBASIC's encoding of long integers
'over 2,147,483,647 as being negative. Pass a pointer to a microsecond RECORD.
'The function also puts the microsecond record into a double precision variable.
  DIM bigtime#, mostime#, lesstime#, thetime.longwatch
LOCAL FN correctime#(recptr&)
  thetime;_longwatch = recptr&
  IF thetime.nlowlong& < 0 THEN lesstime# = thetime.nlowlong& + 4294967295.0 ELSE lesstime# = thetime.nlowlong&
  IF thetime.nhighlong& < 0 THEN mostime# = thetime.nhighlong& + 4294967295.0 ELSE mostime# = thetime.nhighlong&
  bigtime# = 4294967296*mostime# + lesstime#
END FN = bigtime#

Bryan Bremner


Hi, folks. I just wanted to share a quick story about Frank Turovich, FN Microseconds, and me. This was brought to mind by the discussion about a Microsecond timer, and Frank's notice that Sentient Fruit is closing up. (I was late in reading through my messages, and just recently plowed through the backlog.)

In early 1995 a fellow posted a request for help on a Mac newsgroup. He was a film editor in Australia, and wanted to have an on-screen stopwatch that could run accurately in the background. I figured that would be a nothing to write in FB using ticks (at 60 ticks/second), so I quickly compiled an application for him. He liked it, but found it was inaccurate over periods of time on the order of an hour. So I looked in Inside Macintosh, found FN Microseconds, but didn't know how to write the trap. I then called Zedcor, and spoke to Frank for the first & last time to this day. While I was on the phone, he looked through his copy of IM, and told me what to do. He was so nice about it, it makes me smile to this day just remembering his warm drawl. Well, I used the function (posted below), the film editor found the new version satisfactorily accurate, and I've had the satisfaction of not only helping the editor, but the FB community as well. You see, Frank posted the trap & how to use it, and that's where many of you learned of it.

Even though it was only a little thing for Frank, it meant a lot to me (I wouldn't have been able to figure out the trap on my own), and I know you folks appreciate how a little piece of advice can save hours of frustration in programming.

Alan Weiss

DIM RECORD longwatch 'record for microsecond
  DIM nhighlong&
  DIM nlowlong&
DIM END RECORD.longwatch

DIM startime.longwatch

END GLOBALS

LOCAL MODE
'To use this procedure you should have a record set up that
'is two longs (record.long1&, record.long2&).
'Pass the pointer to this record in recptr&
LOCAL FN microsecond(recptr&)
  ` MOVE.L ^recptr&, -(sp) 'move recptr& onto stack
  ` DC.W $A193,$225F,$22C8,$2280 'execute the procedure
END FN

CLEAR LOCAL MODE
'this function corrects for FutureBASIC's encoding of long integers
'over 2,147,483,647 as being negative. Pass a pointer to a microsecond record.
'The function also puts the microsecond record into a double precision variable.
  DIM bigtime#, mostime#, lesstime#, thetime.longwatch
LOCAL FN correctime#(recptr&)
  thetime;_longwatch = recptr&
  IF thetime.nlowlong& < 0 THEN lesstime# = thetime.nlowlong& + 4294967295.0 ELSE lesstime# = thetime.nlowlong&
  IF thetime.nhighlong& < 0 THEN mostime# = thetime.nhighlong& + 4294967295.0 ELSE mostime# = thetime.nhighlong&
  bigtime# = 4294967296*mostime# + lesstime#
END FN = bigtime#

'---------------------------main-----------------------
DIM reconeptr&, mybigdbl#

WINDOW #1, "Micro Timer"
PRINT
reconeptr& = @startime
FN microsecond(reconeptr&)

mybigdbl# = FN correctime#(reconeptr&)
PRINT "It has been " mybigdbl#; " microseconds since bootup"
PRINT "That is, "mybigdbl#/1000000 " seconds."
PRINT
PRINT "(click to exit)"
DO
UNTIL MOUSE(_down)
END