[comp.sys.amiga.tech] Micro Timing Critical sections HELP!

thyssen@batserver.cs.uq.oz.au (Anthony Thyssen) (09/20/90)

   Hello AmigaLand,
		   I am desperately tring to do some timing of a
section of C code and any help would be appreciated.

   Currently I am using both CIA-B timers (linked) to count pulses on
the `PHI2' or in 68000 parlance `E' line. This gives a timer able to
measure periods of up to about 1 hour! duration.

   I calculated that the `E' line should be runing at .715Mhz (1/10th
of cpu clock rate) and physical measurments (a stop watch over ~20mins)
give a figure of .709 +/- .001 Mhz (3 measurements were made).

   Timing a fixed loop of code (see below) however produced varing
results which I beleave is due to the interupt handling of the CPU.

IE with the full screen visible this timed to about 42440 +/- 10 `E' ticks.
Moveing the screen then so only the title bar was showing (while timing)
produced a much lower value (varing a good deal) of 40200 +/- 60 `E' ticks.

I am using Disable() during the timed period to stop other tasks. 

QUESTIONS :-
 1)  What is the differance bettween Disable-Enable
   and Forbid-Permit exec library calls?
 2)  How do you blank the screen?
 3)  Is there any other interupts which can be disabled? How?
 4)  Under the above can memory still be allocated/deallocated - Important?
 5)  Any other comments.

  Anthony Thyssen - (Dragon Computing!)         thyssen@batserver.cs.uq.oz.au
-------------------------------------------------------------------------------
      In some parts of the city curiosity didn't just kill the cat,
    It threw it in the river with lead weights tied to its feet.
						-- Terry Pratchett "Sourcery"
-------------------------------------------------------------------------------

ridder@elvira.enet.dec.com (Hans Ridder) (09/21/90)

In article <4934@uqcspe.cs.uq.oz.au> thyssen@batserver.cs.uq.oz.au writes:
>   I calculated that the `E' line should be runing at .715Mhz (1/10th
>of cpu clock rate) and physical measurments (a stop watch over ~20mins)
>give a figure of .709 +/- .001 Mhz (3 measurements were made).

Since it looks like you are down-under, are you doing this on a PAL
Amiga?  I don't remember the exact frequency, but I think PAL Amigas run
at 7.09MHz (instead of 7.15MHz), giving an E clock of .709MHz.  This is
well documnted in the 1.3 RKM's, I believe.

>   Timing a fixed loop of code (see below) however produced varing
>results which I beleave is due to the interupt handling of the CPU.
>
>IE with the full screen visible this timed to about 42440 +/- 10 `E' ticks.
>Moveing the screen then so only the title bar was showing (while timing)
>produced a much lower value (varing a good deal) of 40200 +/- 60 `E' ticks.

My first guess is that your code was running in Chip ram, thus
contending with screen (and other) DMA.  It would be best if you could
run in Fast ram (if you have any).

Someone else posted about having troubles with repeatable timing,
although I think he was having the timer set an interrupt, and found
that something in the system was disabling interrupts (Disable()) for a
long time, so his interrupt response time was erratic.  (Is that a
run-on sentence, or what?)

>QUESTIONS :-
> 1)  What is the differance bettween Disable-Enable
>   and Forbid-Permit exec library calls?

Put simply, Disable() shuts off all interrupts to the processor.  This
call should only be used when you want to change things which are
accessed by interrupt routines.  Forbid() just stops task switching.
This call should be used when changing things other *tasks* (or
processes) access.  Beware that a Forbid() can be "broken" (i.e. another
task might run) if you do anything which causes a Wait().  You probably
don't want to do any DOS I/O (Read(), printf(), etc.) during a Forbid().

> 2)  How do you blank the screen?

I'm not sure what you mean here.  If you just want to "shut off" the
display DMA, there is a macro (in the graphics includes, I think) called
OFF_DISPLAY, or something like that.  Be sure to turn the display back
on when you're done.

> 3)  Is there any other interupts which can be disabled? How?

The Amiga is *full* of interrupts.  If you don't want anything else to
bother you, use Disable().  Note that the system time (and probably
other things) will stop during a Disable(), so do this sparingly and
probably not in production code.

> 4)  Under the above can memory still be allocated/deallocated - Important?

If you asking if memory can be allocated/deallocated during a Disable(),
sure.  The only time you should *not* do any memory
allocation/deallocation is *inside* an interrupt handler.  (Because you
could have interrupted someone elses allocation/deallocation.)

> 5)  Any other comments.

Sounds like you need to get/read the Rom Kernel Manuals, published by
Addison-Wesley.

>  Anthony Thyssen - (Dragon Computing!)         thyssen@batserver.cs.uq.oz.au

-hans
------------------------------------------------------------------------
  Hans-Gabriel Ridder			Digital Equipment Corporation
  ridder@elvira.enet.dec.com		Customer Support Center
  ...decwrl!elvira.enet!ridder		Colorado Springs, CO

djh@neuromancer.metaphor.com (Dallas J. Hodgson) (09/21/90)

In article <4934@uqcspe.cs.uq.oz.au> thyssen@batserver.cs.uq.oz.au writes:
>
>
<stuff about timing 'C' code deleted>

>I am using Disable() during the timed period to stop other tasks. 
>
>QUESTIONS :-
> 1)  What is the differance bettween Disable-Enable
>   and Forbid-Permit exec library calls?
> 2)  How do you blank the screen?
> 3)  Is there any other interupts which can be disabled? How?
> 4)  Under the above can memory still be allocated/deallocated - Important?
> 5)  Any other comments.
>

1) Disable() turns off interrupts. Forbid() disables task switching.
2) Throw up a 1-bitplane black screen. Or, disable video DMA with
   the OFF_DISPLAY (sp?) macro.
3) Sure, you can disable anything you want. I think you'll understand more
   if you read:
     a) The Amiga Hardware Reference Manual
     b) The Amiga Rom Kernel Manual: Exec
     c) The Guru's Guide to the Amiga : Interrupts, by Carl Sassenrath
4) Possibly, but I'd warn against it. Could break in the future.

Nice sig.
+----------------------------------------------------------------------------+
| Dallas J. Hodgson               |     "This here's the wattle,             |
| Metaphor Computer Systems       |      It's the emblem of our land.        |
| Mountain View, Ca.              |      You can put it in a bottle,         |
| USENET : djh@metaphor.com       |      You can hold it in your hand."      |
+============================================================================+
| "The views I express are my own, and not necessarily those of my employer" |
+----------------------------------------------------------------------------+

daveh@cbmvax.commodore.com (Dave Haynie) (09/21/90)

In article <4934@uqcspe.cs.uq.oz.au> thyssen@batserver.cs.uq.oz.au writes:

>   I calculated that the `E' line should be runing at .715Mhz (1/10th
>of cpu clock rate) and physical measurments (a stop watch over ~20mins)
>give a figure of .709 +/- .001 Mhz (3 measurements were made).

You're right, actually, on both accounts. If you have a PAL machine, the 
CPU clock is 7.09MHz, so you get a 0.709MHz E clock.  If you have an NTSC
machine, you have a 7.159MHz CPU clock, which results in a 0.716MHz E clock.

>   Timing a fixed loop of code (see below) however produced varing
>results which I beleave is due to the interupt handling of the CPU.

There are a variety of reasons why any arbitrary chunk of code will take
varying amounts of time to execute.  The most obvious reason is that Amiga
CPUs vary from 7.09MHz 68000s to 50MHz 68030s.  Thus, the policy that no 
CPU-speed dependent code is permitted in Amiga applications starts to make
some real-world sense.  If you need timing, use a timer, which will be at
least reasonably consistent (like, within 1% or so) between all Amigas.

>QUESTIONS :-
> 1)  What is the differance bettween Disable-Enable
>   and Forbid-Permit exec library calls?

Forbid()/Permit() disables multitasking -- it lets you hog the CPU, for 
whatever reasons.  In general, the only valid reason for this is that you have
a chunk of code that's examining some shared data structures that aren't
locked by a semaphore.  Disable()/Enable() turn off all interrupt processing,
which as a result also happens to disable multitasking.  Some I/O devices will
use this, but there's just about no situation in which an application program
will use these functions.

> 3)  Is there any other interupts which can be disabled? How?

Disable()/Enable(), by definition, will disable all valid interrupts.  Or, to
invert this argument, interrupts that don't get disabled by Disable() aren't
supported by the AmigaOS.  The only such interrupts you could get that are
members of this class are expansion-board-generated INT1*, INT4*, INT5*, or
INT7* on an A2000.

> 4)  Under the above can memory still be allocated/deallocated - Important?

Memory can be allocated and freed during a Forbid(), and I believe during a
Disable() as well, though I have never used that one myself.

>  Anthony Thyssen - (Dragon Computing!)         thyssen@batserver.cs.uq.oz.au

So you know your dragons.  Think of the OS as you walking down the road,
unarmed.  Forbid() would be like your average angry Wyvern meeting you on
this road.  Disable() is more like Smaug or Tiamat coming along to greet
you.
-- 
Dave Haynie Commodore-Amiga (Amiga 3000) "The Crew That Never Rests"
   {uunet|pyramid|rutgers}!cbmvax!daveh      PLINK: hazy     BIX: hazy
      Get that coffee outta my face, put a Margarita in its place!

uzun@pnet01.cts.com (Roger Uzun) (09/22/90)

>> Dave haynie writes that an application need never use Disable()/Enable()
Actually this is not true.  When I wrote a interrupt handler to strip
off mousevents from the input.device queue, I was "pruning" the linked
list of events streaming in, (using the IND_ADDHANDLER function of
the input.device).  I found that if MASSIVE joystick twitching occurred
while pruning this linked list of events, the linked list pruning
could be interrupted in a critical section of removing one of the
port 1 (mouseport) events, and this caused a system crash (only
when doing 6 bitplane anims with all sprites enabled, when I
had 5 bitplane anims with no sprites enabled, I could not get
it to crash).  To get around this I had to replace
the the Disable/Enable sequence in the int handler with a forbid/permit
sequence, then no crashes were possible.

-Roger

UUCP: {hplabs!hp-sdd ucsd nosc}!crash!pnet01!uzun
ARPA: crash!pnet01!uzun@nosc.mil
INET: uzun@pnet01.cts.com

thyssen@batserver.cs.uq.oz.au (Anthony Thyssen) (09/22/90)

   Thanks to All who replied to my list of questions - I now present
The testing code I am using to do a Timing of a empty loop of
C code. It compiles under lattice 5.4 without options (DONOT use the
-O (optimizer) option as that  removes the empty loop and then the
start timer assign (poke).  Using OFF_DISPLAY in the start timer macro
worked to stop the large variance in the timings due to the vidio DMA's
(It does however cause the screen to flash but I expected that) 

   Note the timed sections DONOT do any I/O or waits - The only system call
made is to allocate/deallocate memory. The code I am timing is
data structure routines for my honors project. (Skiplists, Red Black Trees,
Binary Trees, Prioity Queues, ....).

   The Timing still varies but not to a large extent.
Eg in the timing of the empty 10000 time loop varied over the range
                          40096 - 40104
This seems however to depend on the amout of disk activity due to the
loading of the command - but I am not positive. I'll have to do some
tests from ram to be sure.

   Here is the code for my timing routines. and a test program.
This is released for comment only. Donot put on BBS's or hand out.
After the code is finialized I'll release it to Comp.sources.amiga
for general distrubution.
  I'll also release the Data Structures Code sometime but not soon.

  Anthony Thyssen - (Dragon Computing!)         thyssen@batserver.cs.uq.oz.au
-------------------------------------------------------------------------------
     `One afternoon we were running the Khronal Dungeon, and we opened
   a door and found ourselves looking out into the living room where we
   were playing.  One of the characters shot the Game Master with a
   crossbow bolt, and the whole dungeon dissappeared!'   -- "Dream Park"
-------------------------------------------------------------------------------

================= CODE STARTS HERE (3 files) ===============

::::::::::::::
amiga_timer.c
::::::::::::::
/********************************************************************\
**                             _________________________________    **
**   A n t h o n y            |________    __    __    _________|   **
**                                     |  |o_|  |o_|  |             **
**           T h y s s e n           __|   __    __   |__           **
**                                __|   __|  |  |  |__   |__        **
**  `` Dragon Computing! ''    __|   __|     |  |     |__   |__     **
**                            |_____|        |__|        |_____|    **
**                                                                  **
\********************************************************************/
/*
**   This is the timing C subroutines for the amiga computer.
** Note that the start and stop timer is a macro in the header
** file to speed the timing overhead.
**           This is an EXAMPLE only - Not a final release
*/
#include "amiga_timer.h"

static UBYTE CIACRAsave, CIACRBsave;
void *ciab_resource;

void
Open_Timer()
{  /* save info on current timer setup */
  ciab_resource = OpenResource(CIABNAME);
  CIACRAsave = ciab.ciacra;
  CIACRBsave = ciab.ciacrb;
  ciab.ciaicr = 0xff &~CIAICRF_TA &~CIAICRF_TB; /* disable timer interupts */
}

void
TimerPrepare()
{ /* prepare the timer to be started */
  ciab.ciacra=(CIACRAsave&(CIACRAF_TODIN|CIACRAF_SPMODE)) | CIACRBF_IN_PHI2;
  ciab.ciacrb=(CIACRBsave & CIACRBF_ALARM) | CIACRBF_IN_TA | CIACRBF_START;
  ciab.ciatalo = ciab.ciatahi =
  ciab.ciatblo = ciab.ciatbhi = (UBYTE)0xff; /* start at value -1 */
}

ULONG
TimerRead()
{
  register ULONG ticks;
  ticks =              ciab.ciatbhi;
  ticks = (ticks<<8) | ciab.ciatblo;
  ticks = (ticks<<8) | ciab.ciatahi;
  ticks = (ticks<<8) | ciab.ciatalo;
  ticks = ~ticks;          /* negate and -1 */
  return( ticks );    /* time = ticks/clock_rate (.709MHz) */
}

void
Close_Timer()
{
  ciab.ciacra = CIACRAsave;
  ciab.ciacrb = CIACRBsave;
  ciab.ciaicr = (UBYTE)0xff;
}

::::::::::::::
amiga_timer.h
::::::::::::::
/********************************************************************\
**                             _________________________________    **
**   A n t h o n y            |________    __    __    _________|   **
**                                     |  |o_|  |o_|  |             **
**           T h y s s e n           __|   __    __   |__           **
**                                __|   __|  |  |  |__   |__        **
**  `` Dragon Computing! ''    __|   __|     |  |     |__   |__     **
**                            |_____|        |__|        |_____|    **
**                                                                  **
\********************************************************************/
/*
**    Header file to define the code for timeing sections of C code
** on the amiga.  It includes macros for starting and stopping and
** restarting the timer.
**           This is an EXAMPLE only - Not a final release
*/
#include <exec/types.h>          /* general types */
#include <hardware/cia.h>        /* cia stuff */
#include <resources/cia.h>
#include <hardware/custom.h>     /* stuff for ON/OFF DISPLAY */
#include <hardware/dmabits.h>
#include <graphics/gfxmacros.h>
#include <proto/exec.h>          /* do library calls direct */

extern struct CIA    __far ciab;       /* structure for CIA-B chip */
extern struct Custom __far custom;     /* DMA chip - ON/OFF_DISPLAY */

extern void  Open_Timer();    /* initialize timers */
extern ULONG TimerRead();     /* read timers */
extern void  Close_Timer();   /* return timers to system */

/* start timing - Multitasking Disabled */
#define TimerStart() \
  { TimerPrepare(); OFF_DISPLAY; Disable(); ciab.ciacra |= CIACRAF_START; }

/* restart timing - continue the timing from where it left off */
#define TimerRestart() \
  { OFF_DISPLAY; Disable(); ciab.ciacra |= CIACRAF_START; }

/* Stop timer - restore Multitasking */
#define TimerStop() \
  { ciab.ciacra &= ~CIACRAF_START; Enable(); ON_DISPLAY; }


/* The following is to prepare the timer as part of TimerStart macro */
extern void  TimerPrepare();  /* get timer ready to start */

::::::::::::::
timertest.c
::::::::::::::
/*********************************************************************\
**                               ________________________________    **
**    A n t h o n y             |________    __    __    ________|   **
**                                       |  |o_|  |o_|  |            **
**            T h y s s e n            __|   __    __   |__          **
**                                  __|   __|  |  |  |__   |__       **
**   `` Dragon Computing ! ''    __|   __|     |  |     |__   |__    **
**                              |_____|        |__|        |_____|   **
**                                                                   **
\*********************************************************************/
/*
**   Test the timer routines on the amiga
**           This is an EXAMPLE only - Not a final release
*/
#include <stdio.h>
#include "amiga_timer.h"

char input[100];

main()
{
  register int i;
  printf("Timing...\n"); fflush(stdout);
  Open_Timer();                                /* initialize the timer */
  TimerStart();                                /* start timing */
    for(i=0; i<10000; i++);

  TimerStop();                                 /* stop timing */
  printf("Stopped -> %lu \n", TimerRead() ); /* read timer */
  fflush(stdout);
  Close_Timer();                               /* return timer */
  return(0);
}

/*================ END OF CODE ================*/

barnettj@pookie.crd.ge.com (Janet A Barnett) (09/23/90)

In article <14567@cbmvax.commodore.com> daveh@cbmvax.commodore.com (Dave Haynie) writes:
> Disable()/Enable() turn off all interrupt processing,
>which as a result also happens to disable multitasking.
>
>Disable()/Enable(), by definition, will disable all valid interrupts.  Or, to
>invert this argument, interrupts that don't get disabled by Disable() aren't
>supported by the AmigaOS.  The only such interrupts you could get that are
>members of this class are expansion-board-generated INT1*, INT4*, INT5*, or
>INT7* on an A2000.
>
Here is my understanding of Disable(): Rather than set the CPU's interrupt 
mask to 0x7, the custom chip register INTENA is
written such that no interrupt requests are allowed.  Here is my question:
Does this actually prevent interrupting devices (such as the video circuitry
at the start of vertical blanking) from causing a transition of the CPU's
IPL lines?  To put this question another way, is Disable() a logical
function wherein interrupts of the CPU are not physically disabled but
rather simply masked out by RTEing immediately or does the interrupt
control on the custom chip actually block IPL transitions to the CPU?

I wanna know.

p554mve@mpirbn.mpifr-bonn.mpg.de (Michael van Elst) (09/24/90)

In article <4969@uqcspe.cs.uq.oz.au> thyssen@batserver.cs.uq.oz.au writes:
>void
>Open_Timer()
>{  /* save info on current timer setup */
>  ciab_resource = OpenResource(CIABNAME);
>  CIACRAsave = ciab.ciacra;
>  CIACRBsave = ciab.ciacrb;
>  ciab.ciaicr = 0xff &~CIAICRF_TA &~CIAICRF_TB; /* disable timer interupts */
>}

As far as I know you have to allocate the interrupt associated with the
timer to use the timer registers. Since opening the cia resource will
not grant exclusive access to the cia your code might run into problems
when more than one application tries to use the timer.
The interrupt can be allocated with a call to AddICRVector() (sp ?)..

Regards,
-- 
Michael van Elst
UUCP:     universe!local-cluster!milky-way!sol!earth!uunet!unido!mpirbn!p554mve
Internet: p554mve@mpirbn.mpifr-bonn.mpg.de
                                "A potential Snark may lurk in every tree."