
                                [1mA.I.B.B.[22m
                     [1mAmiga Intuition Based Benchmarks[22m
           [1mA system performance evaluation utility for the Amiga[22m

                       [1mProgram Release Version 4.61[22m
                     [1mCopyright 1991,1992 LaMonte Koop[22m

                     Benchmark code examples and notes

    The code used for AIBB's benchmarking suite is rather simple in nature,
but in order to provide a better view of what exactly each test does, a more
thorough explanation for each is given in this document.  In addition, a
'pseudo-C' code representation of each test is also supplied.  This
representation is not the full function itself, but rather a view of it
which highlights the actual test material.  What is missing from these
representations is mostly initialization and cleanup code, and in some places
the full C syntax is not applied as used in AIBB itself.  However, this should
give a fairly good picture of what is being done by AIBB during test
performance.
    It should be noted that the code used is by no means optimized in some
areas.  Where optimization was prudent, it was used, but in some places this
defeats the purpose.

==============================================================================

                                [1mWritePixel[22m

    The WritePixel test is a very simple display of a given system's graphics
throughput.  It mainly deals with the operating system calls SetAPen()
( set the primary pen color ), and WritePixel() ( set a pixel in the current
pen color ).  This is a basic test of the efficiency of the operating system
functions, as well as the speed of the custom hardware on the Amiga in these
simple matters.  Systems where the operating system kernel resides in a fast
memory medium, as well as those which have more efficiency access to CHIP RAM
resources will have the advantage with this test.  The code representation
for this test is given below:


WritePixel_Test()
{
    struct Screen *WPScreen;
    struct RastPort *rp;
    UWORD x;
    UWORD y;
    ULONG nulltime;

    /*
     * Although not shown, the screen and rastport variables are first set
     * up, then the test procedes at the following point....
     */

    START_TEST_TIMER;

    SetAPen(rp,1);
    for(y = 0; y < 200; y++)
    {
       for(x = 0; x < 320; x++)
       {
          WritePixel(rp,x,y);
       }
    }
    SetAPen(rp,0);
    for(x = 0; x < 320; x++)
    {
       for(y = 0; y < 200; y++)
       {
          WritePixel(rp,x,y);
       }
    }
    SetAPen(rp,1);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,319,y);
    }
    SetAPen(rp,0);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,320,y);
    }
    SetAPen(rp,1);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,319,y);
    }
    SetAPen(rp,0);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,320,y);
    }
    SetAPen(rp,1);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,319,y);
    }
    SetAPen(rp,0);
    for(y = 0; y < 200; y++)
    {
       Move(rp,0,y);
       Draw(rp,320,y);
    }
    SetAPen(rp,1);
    for(y = 0; y < 200; y++)
    {
       for(x = 0; x < 320; x++)
       {
          WritePixel(rp,x,y);
       }
    }
    SetAPen(rp,0);
    for(x = 0; x < 320; x++)
    {
       for(y = 0; y < 200; y++)
       {
          WritePixel(rp,x,y);
       }
    }
    STOP_TEST_TIMER;

    /* That concludes the actual test code portion of this function */
    .................................................................
}

==============================================================================

                                  [1mIMath[22m

    IMath is a test of the primary integer/logical operational efficiency of
a system.  Various integer arithmetic and logical function are performed in
succession, and the calculations timed within a loop.  The loop variable
itself is used within the calculations in order to provide a dynamic quality
to the generated code, instead of static values being used at all times.
This test performs its operations on longword ( 32-bit ) values exclusively.


IMath_Test()
{
    LONG i;
    LONG a = 2;
    LONG b = 45;
    LONG c = 22;

    START_TEST_TIMER;

    for(i=0; i < 100000 ; i++)
    {
       a = (a * b) + i;
       b = (a * b) + (2 * i);
       c += ((c * a) + b) + i;
       c -= (((i + 1) - (a * b)) & ((b / a) | (i % 10))) + i;
       c += ((b * c) - (b / a) - i) ^ i + c;
       c -= (b / a) * (i + b);
       c += (((b / a) * c) - i) ^ i + c;
       c -= (((i + 1) - (a * b)) & ((b / a) | (i % 5))) - (5 * i);
       c += (b / a) * i;
       c -= (((b / a) * c) - i) ^ i + c;
       c += (((i + 1)-(a * b)) & ((b / a) | (i % 7))) - i;
       c -= (b / a) * (i - b);
       b = (a * b) - (b ^ a) - i;
       a = (a * b) + i;
       c += ((b / a) - i) ^ i;
    }

    STOP_TEST_TIMER;

    /*
     *  At this point a global 'dummy' variable is used to assure that
     *  code above is not optimized out.  This makes a global optimizer
     *  believe the above results are needed in order to assign the
     *  dummy variable a value
     */

    TestDummy = a+b+c;

    /* The actual test code has concluded at this point */
    .................................................................
}

==============================================================================

                                  [1mMatrix[22m

    This is AIBB's integer longword matrix manipulation test.  Three matrices
are used in a variety of operations, with stress being placed upon matrix
manipulation ( data movement ) functions, as these are often primary functions
performed on matrices.  As the data here can not be kept entirely in registers
for arithmetic manipulation, this test gives an indication of system
performance when many data accesses are required outside of register values.
The functions are also set up as to stress the calculation of data locations
in the test timing.  Note that systems with larger caches ( such as the
MC68040 ) will have a general advantage here, although the matrices are quite
large enough as to not permit them to be entirely cached. The outline function
for the matrix test and its associated functions is given below:


void Matrix_Test()
{
     LONG *MatrixA;
     LONG *MatrixB;
     LONG *MatrixC;
     UWORD i;
     UWORD j;
     UWORD k;

    /*
     * Not shown, but the above LONG pointers are first initialized by
     * allocating 10000 bytes of memory for each and assigning them
     * to point at the base of each 'array'.
     */

    /*
     * The A and B arrays are first filled with values for later use
     */

    for(i=0; i<50; i++)
    {
       for(j=0; j<50; j++)
       {
           MatrixA[50*i+j] = (LONG)i+(LONG)j;
           MatrixB[50*i+j] = (LONG)(i+j) * (LONG)(j-i);
       }
    }

    START_TEST_TIMER;

    /*
     * Here is the actual test code.  More emphasis is placed upon
     * matrix data movement than arithmetic operation as many matrix-
     * manipulation applications involve movement more than arithmetic
     * (though, execeptions seem to be the rule here :) ).
     * Though a purpose doesn't seem to be in mind here, it can give a
     * general manipulation 'feel' for the system.
     */

    for(k=0; k < 50; k++)
    {
       matrix_mult(MatrixA,MatrixB,MatrixC,50,50);
       for(i=0; i<50; i++)
       {
          matrix_row_swap(MatrixC,i,49-i,50);
          matrix_col_swap(MatrixC,49-i,i,50);
       }
       matrix_add(MatrixC,MatrixA,MatrixB,50,50);
       matrix_sub(MatrixB,MatrixA,MatrixC,50,50);
       matrix_transpose(MatrixC,MatrixA,50,50);
    }

    STOP_TEST_TIMER;

    /*
     * That concludes the test code proper.  Clean up operations are
     * inserted following, and are not shown
     */
     ................................................................
}

/*
 * This function swaps rows in a matrix.
 */

void matrix_row_swap(LONG *mat, UWORD ra, UWORD rb, UWORD ncols)
{
    UWORD c;
    LONG t;

    for(c=0; c < ncols; c++)
    {
       t = mat[ra*ncols+c];
       mat[ra*ncols+c] = mat[rb*ncols+c];
       mat[rb*ncols+c] = t;
    }
}

/*
 * Same as above, but for column-swapping.
 */

void matrix_col_swap(LONG *mat, UWORD ca, UWORD cb, UWORD nrows)
{
    UWORD r;
    LONG t;

    for(r=0; r < nrows; r++)
    {
       t = mat[r*nrows+ca];
       mat[r*nrows+ca] = mat[r*nrows+cb];
       mat[r*nrows+cb] = t;
    }
}

/*
 * Add the contents of two matrices, and store the result in a third.
 * Equivalent to [C] = [A] + [B]
 */

void matrix_add(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] + matB[r*cols+c];
       }
    }
}

/*
 * Subtract the contents of two matrices, and store the result in a third.
 * Equivalent to [C] = [A] - [B].
 */

void matrix_sub(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;

    for(r=0; r < rows; r++)
    {
       for(c=0; c<cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] - matB[r*cols+c];
       }
    }
}

/*
 * Subtract the contents of two matrices, and store the result in a third.
 * Equivalent to [C] = [A] * [B].
 */

void matrix_mult(LONG *matA, LONG *matB, LONG *matC, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;

    for(r=0; r<rows; r++)
    {
       for(c=0; c<cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] * matB[r*cols+c];
       }
    }
}

/*
 * Transpose the contents of matrix [B] to matrix [A]
 */

void matrix_transpose(LONG *matA, LONG *matB, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;
    LONG t;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          t = matA[r*cols+c];
          matA[r*cols+c] = matB[r*cols+c];
          matB[r*cols+c] = t;
       }
    }
}

==============================================================================

                                  [1mMemTest[22m

    This function was primarily designed to test only the data movement
efficiency of the system across both CHIP and FAST RAM buses.  CHIP memory
testing vs. FAST memory testing is weighted to favor FAST memory, as
CHIP memory is not used as often ( in the case of the CPU ).  The exception
to this is in CHIP-RAM only systems, where this test will in the end
have all its testing memory located there.  This does end up as a fair
comparison by that end, as since those systems have no FAST RAM, they
must contend with what they do have alone.  The general layout of the
test is given below:


void MemTest()
{
    UBYTE *FMemArray1;
    UBYTE *FMemArray2;
    UBYTE *CMemArray1;
    UBYTE *CMemArray2;

    /*
     * First (not shown), two arrays of 32K in size are allocated and
     * the reserved space split among the pointers above...
     */

     .................................................................

    /*
     * The actual test is a series of function calls, testing longword,
     * word, and byte transfer times.
     */

    START_TEST_TIMER;

    LongWordMemTest((ULONG *)FMemArray1,(ULONG *)FMemArray2,65);
    LongWordMemTest((ULONG *)FMemArray2,(ULONG *)CMemArray1,25);
    LongWordMemTest((ULONG *)CMemArray1,(ULONG *)CMemArray2,15);
    WordMemTest((UWORD *)FMemArray1,(UWORD *)FMemArray2,65);
    WordMemTest((UWORD *)FMemArray2,(UWORD *)CMemArray1,25);
    WordMemTest((UWORD *)CMemArray1,(UWORD *)CMemArray2,15);
    ByteMemTest((UBYTE *)FMemArray1,(UBYTE *)FMemArray2,65);
    ByteMemTest((UBYTE *)FMemArray2,(UBYTE *)CMemArray1,25);
    ByteMemTest((UBYTE *)CMemArray1,(UBYTE *)CMemArray2,15);

    STOP_TEST_TIMER;

    /*
     * Clean up code would be placed in this location.
     */
     ...........................................................
}

/*
 * This function is responsible for LONGWORD memory access testing.
 */

void LongWordMemTest(ULONG *MemArray1, ULONG *MemArray2, UWORD loops)
{
    UWORD i;
    UWORD j;

    for(j=0; j < loops; j++)
    {
       for(i=0; i < 4096; i++)
       {
           *MemArray1++ = *MemArray2++;
       }
       for(i=0; i < 4096; i++)
       {
           *(--MemArray2) = *(--MemArray1);
       }
    }
}

/*
 * This function is responsible for WORD memory access testing.
 */

void WordMemTest(UWORD *MemArray1, UWORD *MemArray2, UWORD loops)
{
    register UWORD i;
    register UWORD j;

    for(j=0; j < loops; j++)
    {
       for(i=0; i < 8192; i++)
       {
           *MemArray1++ = *MemArray2++;
       }
       for(i=0; i < 8192; i++)
       {
           *(--MemArray2) = *(--MemArray1);
       }
    }
}

/*
 * This function is responsible for BYTE memory access testing.
 */

void ByteMemTest(UBYTE *MemArray1, UBYTE *MemArray2, UWORD loops)
{
    UWORD i;
    UWORD j;

    for(j=0; j < loops; j++)
    {
       for(i=0; i < 16384; i++)
       {
           *MemArray1++ = *MemArray2++;
       }
       for(i=0; i < 16384; i++)
       {
           *(--MemArray2) = *(--MemArray1);
       }
    }
}

==============================================================================

                                   [1mSieve[22m

    This test is the basic Sieve of Erosthenes, used often to benchmark system
performance at a basic level.  As the name implies, it is a 'sieve' for
prime numbers, continuing up to the number 8191.  The test is a counting
test, primarily involved in array initialization, and value assignment.


void Sieve()
{
    UWORD k;
    UWORD iter;
    UWORD i;
    UWORD count;
    UWORD prime;
    BOOL flags[8191];

    START_TEST_TIMER;

    for(iter=0; iter < 200; iter++)
    {
       count = 0;
       for(i=0; i < 8191; i++) flags[i] = TRUE;
       for(i=0; i < 8191; i++)
       {
          if(flags[i])
          {
             prime = i + i + 3;
             for(k=i+prime; k < 8191; k += prime) flags[k] = FALSE;
             count++;
          }
       }
    }

    STOP_TEST_TIMER;

    /* End of test code */

    ..................................................................
}

==============================================================================

                                    [1mSort[22m

    A simple sorting test on a 60000 byte array ( arranged as 16-bit WORD
values ).  The algorithm used here is a shell-sort setup, with the array
initialization itself also being part of the timed code.  The sorting is
timed for 5 passes, to allow better resolution in the results. ( lower
numbers of passes tend to be too fast on accelerated systems ).

void Sort()
{
    WORD *sarray;
    WORD gap;
    WORD temp;
    WORD i;
    WORD j;
    BOOL nex;

    /*
     * In initializing for this test, a 60000 byte array is allocated
     * before the actual test code begins.
     */

    ................................................................

    START_TEST_TIMER;

    for(j=0; j < 5; j++)
    {

      /*
        * The array is initialized first.  A non-random spreading setup
        * is used to insure the same values are used for every sorting
        * pass...this lessens the possibility of timing changes due to
        * order dependency of the routine.
        */

       for(i=0; i < 30000; i++) sarray[i] = (i % 2) ? (WORD)30000-i : (WORD)i;

       gap = 30000 / 2;
       do {
         do {
            nex = FALSE;
            for(i=0; i < 30000-gap; i++)
            {
               if(sarray[i] > sarray[i+gap])
               {
                  temp = sarray[i];
                  sarray[i] = sarray[i+gap];
                  sarray[i+gap] = temp;
                  nex = TRUE;
               }
            }
         } while(nex);
         gap /= 2;
       } while(gap);
    }

    STOP_TEST_TIMER;

    /* Clean up code and result calculation should follow at this point. */

    ...................................................................
}

==============================================================================

                                   [1mTGTest[22m

    Text and Graphics Test.  This is a test of the text throughput on the
system in question.  Since OS calls are used again, this will have an advantage
on systems with the OS kernel in a fast memory medium, and will also have
advantage on those systems with more efficiency CHIP RAM access.  There are
also some position variables which are calculated during the test, so this
does not simply show the speed of the various text routines used, but also
the overall efficiency of system when executing the routine's entire job.
A decision step is also involved in drawing mode selection, thus contributing
to the overall view of the text output and calculation efficiency of the
system.


void TGTest()
{
    struct Screen *TTScrn;
    struct Window *TTWin;
    struct RastPort *TTRp;
    UWORD xpos;
    UWORD ypos = 0;
    UWORD scrolls = 0;
    UWORD color = 0;
    UWORD drmd = JAM1;

    /*
     * Initialization for this routine should involve screen/window
     * setup, as well as color selection.  This is not shown, but
     * is assumed.
     */

    TTRp = TTWin->RPort;
    SetDrMd(TTRp,drmd);
    SetAPen(TTRp,color);

    START_TEST_TIMER;

    while(scrolls < 150)
    {
       xpos = 0;
       while(xpos < 600)
       {
          switch(drmd)
          {
             case JAM1 :
                  drmd = JAM2;
                  break;
             case JAM2 :
                  drmd = COMPLEMENT;
                  break;
             case COMPLEMENT :
                  drmd = INVERSVID;
                  break;
             case INVERSVID :
                  drmd = JAM1;
                  break;
          }
          SetDrMd(TTRp,drmd);
          color = (color == 3) ? 0 : color + 1;
          SetAPen(TTRp,(color = (color == 3) ? 0 : color + 1));
          if(drmd != JAM1) SetBPen(TTRp,(color > 1) ? color-2 : color + 1);

          Move(TTRp,xpos,ypos);
          Text(TTRp,TestStr,strlen(TestStr));

          xpos += TextLength(TTRp,TestStr,strlen(TestStr));
       }
       ypos += 9;
       if(ypos > 189)
       {
          ypos = 189;
          ScrollRaster(TTRp,0,9,0,0,640,200);
          scrolls++;
       }
    }

    STOP_TEST_TIMER;

    /* Clean up routines should follow at this point */

    ..................................................................
}

==============================================================================

                                   [1mFMath[22m

    The FMath test is very similar to the IMath test with the exception that
floating point math is the primary interest as opposed to integer operations.
Single-precision operations are utilized for this test.  The rough code
outline is given below:


void FMath()
{
    float a;
    float b;
    float c;
    UWORD i;

    a = 45.43;
    b = 2.22;
    c = 2.0;

    START_TEST_TIMER;

    for(i=0; i < 20000 ; i++)
    {
       a = (a * b) + (float)i;
       c += ((a * b) / (float)i) + 1.0;
       c -= (c / a) - (float)i;
       c += ((c / a) * (float)i) + 1.0;
       a = (a * b) + (float)i;
       c -= (c / a) - (float)i;
       c += ((a * b) / (float)i) + 1.0;
       c -= ((c / a) * (float)i) + 1.0;
       a = (a * b) + (float)i;
       c += (c / a) - (float)i;
       c -= ((a * b) / (float)i) + 1.0;
       c += ((c / a) * (float)i) + 1.0;
       a = (a * b) + (float)i;
       c -= (c / a) - (float)i;
    }

    STOP_TEST_TIMER;

    /*
     *  Again, at this point a global 'dummy' variable is used to assure that
     *  code above is not optimized out.  This makes a global optimizer
     *  believe the above results are needed in order to assign the
     *  dummy variable a value
     */

    TestFltDummy = a+b+c;

    ....................................................................
}

==============================================================================

                                  [1mFMatrix[22m

    The FMatrix test is almost completely identical to the standard integer
matrix test, with the exception that the data being manipulated is double
precision floating point numbers.  The code outline is given below:


void FMatrix()
{
    double *MatrixA;
    double *MatrixB;
    double *MatrixC;
    UWORD i;
    UWORD j;
    UWORD k;

    /*
     * Not shown: The 3 matrices must be allocated ( 12800 bytes each )
     * for the following test.  Next, shown below, matrices A and B are
     * initialized with data.
     */

    for(i=0; i < 40; i++)
    {
      for(j=0; j < 40; j++)
      {
          MatrixA[40*i+j] = (double)(i+j);
          MatrixB[40*i+j] = (double)(i+j) * (double)(j-i);
      }
    }

    /*
     * The actual test code begins below.
     */

    START_TEST_TIMER;

    for(k=0; k < 50; k++)
    {
       fmatrix_mult(MatrixA,MatrixB,MatrixC,40,40);
       for(i=0; i < 40; i++)
       {
          fmatrix_row_swap(MatrixC,i,39-i,40);
          fmatrix_col_swap(MatrixC,39-i,i,40);
       }
       fmatrix_add(MatrixC,MatrixA,MatrixB,40,40);
       fmatrix_sub(MatrixB,MatrixA,MatrixC,40,40);
       fmatrix_transpose(MatrixC,MatrixA,40,40);
    }

    STOP_TEST_TIMER;

    /*
     * Again, clean-up and memory deallocation is performed here, though
     * not shown.
     */

     ..................................................................
}

/*
 * This function swaps rows in a double FP matrix.
 */

void fmatrix_row_swap(double *mat, UWORD ra, UWORD rb, UWORD ncols)
{
    UWORD c;
    double t;

    for(c=0; c < ncols; c++)
    {
       t = mat[ra*ncols+c];
       mat[ra*ncols+c] = mat[rb*ncols+c];
       mat[rb*ncols+c] = t;
    }
}

void fmatrix_col_swap(double *mat, UWORD ca, UWORD cb, UWORD nrows)
{
    UWORD r;
    double t;

    for(r=0; r < nrows; r++)
    {
       t = mat[r*nrows+ca];
       mat[r*nrows+ca] = mat[r*nrows+cb];
       mat[r*nrows+cb] = t;
    }
}

/*
 * Add the contents of two FP matrices, and store the result in a third.
 * Equivalent to [C] = [A] + [B]
 */

void fmatrix_add(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
{
     UWORD r;
     UWORD c;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] + matB[r*cols+c];
       }
    }
}

/*
 * Subtract the contents of two FP matrices, and store the result in a third.
 * Equivalent to [C] = [A] - [B].
 */

void fmatrix_sub(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] - matB[r*cols+c];
       }
    }
}

/*
 * Subtract the contents of two FP matrices, and store the result in a third.
 * Equivalent to [C] = [A] * [B].
 */

void fmatrix_mult(double *matA, double *matB, double *matC, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          matC[r*cols+c] = matA[r*cols+c] * matB[r*cols+c];
       }
    }
}

/*
 * Transpose the contents of FP matrix [B] to FP matrix [A]
 */

void fmatrix_transpose(double *matA, double *matB, UWORD rows, UWORD cols)
{
    UWORD r;
    UWORD c;
    double t;

    for(r=0; r < rows; r++)
    {
       for(c=0; c < cols; c++)
       {
          t = matA[r*cols+c];
          matA[r*cols+c] = matB[r*cols+c];
          matB[r*cols+c] = t;
       }
    }
}


==============================================================================

                                  [1mSavage[22m

    The Savage benchmark is a test almost exclusively consisting of floating-
point transcendental functions.  It is a fairly well known test, used a fair
amount for basic trancendental function evaluation.  It is very simple in
nature, as can be seen below:

void Savage()
{
    UWORD i;
    double a = 1.0L;

    START_TEST_TIMER;

    for(i=0; i < 40000; i++)
    {
        a = tan(atan(exp(log(sqrt(a*a))))) + 1.0L;
    }

    STOP_TEST_TIMER;

    /*
     * And that's the basic essence to the test...
     */

     ...........................................................
}

===========================================================================
                               [1mWhetstone[22m

    The Whetstone test is a fairly popular, albeit older, test of system
performance.  Because it deals with floating point as well as other
areas, it is placed in the floating point test category.  The test has
been slightly modified in that the accuracy tests it does (checks) have
been replaced...a function call is still used to maintain the integrity of
the test, but accuracy is not a testing concern in this setup.

void Whetstone_Test()
{
    BOOL tempbool;

    START_TEST_TIMER;

    n1_O  = 2L * wt_O;
    n2_O  = 10L * wt_O;
    n3_O  = 14L * wt_O;
    n4_O  = 345L * wt_O;
    n5_O  = 0L;
    n6_O  = 95L * wt_O;
    n7_O  = 32L * wt_O;
    n8_O  = 800L * wt_O;
    n9_O  = 616L * wt_O;
    n10_O = 0L;
    n11_O = 93L * wt_O;

    /***********************************/
    /*  MODULE  1: Simple Identifiers  */
    /***********************************/

    xx_O_d.one   =  1.0;
    xx_O_d.two   = -1.0;
    xx_O_d.three = -1.0;
    xx_O_d.four  = -1.0;

    for(i_O = 0L; i_O < n1_O; i_O++)
    {
       xx_O_d.one   = ( xx_O_d.one + xx_O_d.two + xx_O_d.three - xx_O_d.four ) * T;
       xx_O_d.two   = ( xx_O_d.one + xx_O_d.two - xx_O_d.three + xx_O_d.four ) * T;
       xx_O_d.three = ( xx_O_d.one - xx_O_d.two + xx_O_d.three + xx_O_d.four ) * T;
       xx_O_d.four  = (-xx_O_d.one + xx_O_d.two + xx_O_d.three + xx_O_d.four ) * T;
    }

    norm_O_d = sqrt(sqr(xx_O_d.one)+sqr(xx_O_d.two)+sqr(xx_O_d.three)+sqr(xx_O_d.four));
    tempbool = ((fabs(norm_O_d - exp(0.35735-n1_O*6.1e-5))/norm_O_d) <= 0.1);
    Check(1,tempbool);

   /*******************************/
   /*  MODULE  2: Array Elements  */
   /*******************************/

    e1_O_d[0] =  1.0;
    e1_O_d[1] = -1.0;
    e1_O_d[2] = -1.0;
    e1_O_d[3] = -1.0;

    for(i_O=0L; i_O < n2_O; i_O++)
    {
       e1_O_d[0] = ( e1_O_d[0] + e1_O_d[1] + e1_O_d[2] - e1_O_d[3] ) * T;
       e1_O_d[1] = ( e1_O_d[0] + e1_O_d[1] - e1_O_d[2] + e1_O_d[3] ) * T;
       e1_O_d[2] = ( e1_O_d[0] - e1_O_d[1] + e1_O_d[2] + e1_O_d[3] ) * T;
       e1_O_d[3] = (-e1_O_d[0] + e1_O_d[1] + e1_O_d[2] + e1_O_d[3] ) * T;
    }

    norm_O_d = sqrt(sqr(e1_O_d[0])+sqr(e1_O_d[1])+sqr(e1_O_d[2])+sqr(e1_O_d[3]));
    tempbool = ((fabs(norm_O_d - exp(0.35735-n2_O*6.1e-5))/norm_O_d) <= 0.1);
    Check(2,tempbool);

    /*************************************/
    /*  MODULE  3: Array as a Parameter  */
    /*************************************/

    t3_O_d = 1.0 / T;

    for(i_O = 0; i_O < n3_O; i_O++) pa(e1_O_d);

    norm_O_d = sqrt(sqr(e1_O_d[0])+sqr(e1_O_d[1])+sqr(e1_O_d[2])+sqr(e1_O_d[3]));
    tempbool = ((fabs(norm_O_d - exp(0.35735-(n3_O*6+n2_O)*6.1e-5))/norm_O_d) <= 0.1);
    Check(3,tempbool);

    /**********************************/
    /*  MODULE  4: Conditional Jumps  */
    /**********************************/

    jj_O = 1L;

    for(i_O = 0; i_O < n4_O; i_O++)
    {
       if(jj_O == 1L)
          jj_O = 2L;
       else
          jj_O = 3L;
       if(jj_O > 2L)
          jj_O = 0L;
       else
          jj_O = 1L;
       if(jj_O < 1L)
          jj_O = 1L;
       else
         jj_O = 0L;
    }
    tempbool = (jj_O == (!(wt_O & 1L)));
    Check(4,tempbool);

    /***********************************/
    /*  MODULE  6: Integer Arithmetic  */
    /***********************************/

    ij_O = 1;
    ik_O = 2;
    il_O = 3;

    for(i_O=0 ; i_O < n6_O; i_O++)
    {
       ij_O =  ij_O * (ik_O - ij_O) * (il_O - ik_O);
       ik_O =  il_O * ik_O - (il_O - ij_O) * ik_O;
       il_O = (il_O - ik_O) * (ik_O + ij_O);

       e1_O_d[il_O-2] = ij_O + ik_O + il_O;
       e1_O_d[ik_O-2] = ij_O * ik_O * il_O;
    }

    tempbool = ((ij_O==1L) && (ik_O==2L) && (il_O==3L));
    Check(6,tempbool);

    /****************************************/
    /*  MODULE  7: Trigonometric Functions  */
    /****************************************/

    x_O_d = 0.5;
    y_O_d = 0.5;

    for(i_O=0L; i_O < n7_O; i_O++)
    {
       x_O_d = T * atan(T2 * sin(x_O_d) * cos(x_O_d) / (cos(x_O_d+y_O_d) + cos(x_O_d-y_O_d) - 1.0));
       y_O_d = T * atan(T2 * sin(y_O_d) * cos(y_O_d) / (cos(x_O_d+y_O_d) + cos(x_O_d-y_O_d) - 1.0));
    }

    tempbool = (((T - wt_O * 0.0015) <= x_O_d) && (x_O_d <= (T - wt_O * 0.0004)) &&
                ((T - wt_O * 0.0015) <= y_O_d) && (y_O_d <= (T - wt_O * 0.0004)));
    Check(7,tempbool);

   /********************************/
   /*  MODULE  8: Procedure Calls  */
   /********************************/

    x_O_d = 1.0;
    y_O_d = 1.0;
    z_O_d = 1.0;

    for(i_O = 1L; i_O <= n8_O; i_O++) p3((double)(y_O_d*(double)i_O),(double)(y_O_d+z_O_d),&z_O_d);
    tempbool = ((fabs(z_O_d - (0.99983352*n8_O - 0.999555651))) <= (n8_O*1.0e-6));
    Check(8,tempbool);

    /*********************************/
    /*  MODULE  9: Array References  */
    /*********************************/

    ij_O = 0;
    ik_O = 1;
    il_O = 2;

    e1_O_d[0] = 1.0;
    e1_O_d[1] = 2.0;
    e1_O_d[2] = 3.0;

    for(i_O=0L; i_O < n9_O; i_O++) p0();

    tempbool = ((e1_O_d[0] == 3.0) && (e1_O_d[1] == 2.0) && (e1_O_d[2] == 3.0));
    Check(9,tempbool);

    /***********************************/
    /*  MODULE 10: Integer Arithmetic  */
    /***********************************/

    jj_O = 2L;
    kk_O = 3L;

    for(i_O=0;i_O<n10_O;i_O++)
    {
       jj_O = jj_O + kk_O;
       kk_O = jj_O + kk_O;
       jj_O = kk_O - jj_O;
       kk_O = kk_O - jj_O - jj_O;
    }
    tempbool = ((jj_O==2) && (kk_O==3));
    Check(10,tempbool);

    /***********************************/
    /*  MODULE 11: Standard Functions  */
    /***********************************/

    x_O_d = 0.75;

    for(i_O = 0L; i_O < n11_O; i_O++) x_O_d = sqrt(exp(log(x_O_d) / T1));

    estimate_O_d = 1.0L - exp(-0.0447L*wt_O + log(0.26L));
    tempbool = ((fabs(estimate_O_d-x_O_d)/estimate_O_d <= (0.0006 + 0.065/(5.0+(double)wt_O))));
    Check(11,tempbool);

   /**************************************/

    STOP_TEST_TIMER;

    /*
     * Cleanup and result calculations are omitted here, as the main
     * portion of the actual test is the concern.
     */

}

static double sqr(register double x)
{
    x *= x;
    return(x);
}

static void pa(register double *e)
{
    register WORD j = 0;

    do {
         e[0] = ( e[0] + e[1] + e[2] - e[3] ) * T;
         e[1] = ( e[0] + e[1] - e[2] + e[3] ) * T;
         e[2] = ( e[0] - e[1] + e[2] + e[3] ) * T;
         e[3] = (-e[0] + e[1] + e[2] + e[3] ) / t3_O_d;
         j++;
    } while(j < 6);
}


static void p0()
{
    e1_O_d[ij_O] = e1_O_d[ik_O];
    e1_O_d[ik_O] = e1_O_d[il_O];
    e1_O_d[il_O] = e1_O_d[ij_O];
}

static void p3(register double x, register double y, register double *z)
{
    x = T * (*z + x);
    y = T * (x + y);
    *z = (x + y) / T2;
}

static BOOL Check(register UWORD ModuleNo, register BOOL Condition)
{
   return((Condition) ? TRUE : FALSE);
}

===========================================================================
                                 [1mFTrace[22m

    The FTrace test is in actuality a portion of a ray-tracing algorithm
set in use as a benchmark.  Its construction is fairly simple, and the
main outline is given below:

BOOL FTrace_CP_N()
{
    WORD iter;
    double od_fline;
    double od_cline;
    ULONG nulltime;

    /*
     * Initialization not shown to focus on the main test itself
     */

    START_TEST_TIMER;

    for(iter=0; iter < LOOPCOUNT; iter++)
    {
       for(paraxial=0; paraxial <= 1; paraxial++)
       {
          trace_line(4,clear_aperture / 2.0L);
          od_sa[paraxial][0] = object_distance;
          od_sa[paraxial][1] = axis_slope_angle;
       }
       paraxial = 0;
       trace_line(3,clear_aperture / 2.0L);
       od_cline = object_distance;
       trace_line(6,clear_aperture / 2.0L);
       od_fline = object_distance;
       aberr_lspher = od_sa[1][0] - od_sa[0][0];
       aberr_osc = 1.0L - (od_sa[1][0] * od_sa[1][1]) /
                          (sin(od_sa[0][1]) * od_sa[0][0]);
       aberr_lchrom = od_fline - od_cline;
       max_lspher = sin(od_sa[0][1]);
       max_lspher = 0.0000926L / (max_lspher * max_lspher);
       max_osc = 0.0025L;
       max_lchrom = max_lspher;
    }

    STOP_TEST_TIMER;

    ..............................................................
}

/*-----------------------------------------------------------------------------*/

void trace_line(register WORD line, register double ray_h)
{
    register WORD i;

    object_distance = 0.0L;
    ray_height = ray_h;
    from_index = 1.0L;

    for(i = 1; i <= current_surfaces; i++)
    {
       radius_of_curvature = s[i][1];
       to_index = s[i][2];
       if(to_index > 1.0L)
          to_index = to_index + ((spectral_line[4] - spectral_line[line]) /
                     (spectral_line[3] - spectral_line[6])) *
                     ((s[i][2] - 1.0L) / s[i][3]);
       transit_surface();
       from_index = to_index;
       if(i < current_surfaces) object_distance = object_distance - s[i][4];
    }
}

/*----------------------------------------------------------------------------*/

void transit_surface()
{
    register double iang;               /* Incidence angle */
    register double rang;
    register double iang_sin;
    register double rang_sin;
    double old_axis_slope_angle;
    double sagitta;

    if(paraxial)
    {
       if(radius_of_curvature != 0.0L)
       {
          if(object_distance == 0.0L)
          {
             axis_slope_angle = 0.0L;
             iang_sin = ray_height / radius_of_curvature;
          }
          else
             iang_sin = ((object_distance - radius_of_curvature) /
                          radius_of_curvature) * axis_slope_angle;

          rang_sin = (from_index / to_index) * iang_sin;
          old_axis_slope_angle = axis_slope_angle;
          axis_slope_angle = axis_slope_angle + iang_sin - rang_sin;
          if(object_distance != 0.0L)
             ray_height = object_distance * old_axis_slope_angle;
          object_distance = ray_height / axis_slope_angle;
          return;
       }
       object_distance = object_distance * (to_index / from_index);
       axis_slope_angle = axis_slope_angle * (from_index / to_index);
       return;
    }

    if(radius_of_curvature != 0.0L)
    {
       if(object_distance == 0.0L)
       {
          axis_slope_angle = 0.0L;
          iang_sin = ray_height / radius_of_curvature;
       }
       else
       {
          iang_sin = ((object_distance - radius_of_curvature) /
                       radius_of_curvature) * sin(axis_slope_angle);
       }
       iang = asin(iang_sin);
       rang_sin = (from_index / to_index) * iang_sin;
       old_axis_slope_angle = axis_slope_angle;
       axis_slope_angle = axis_slope_angle + iang - asin(rang_sin);
       sagitta = sin((old_axis_slope_angle + iang) / 2.0L);
       sagitta = 2.0L * radius_of_curvature*sagitta*sagitta;
       object_distance = ((radius_of_curvature *
                           sin(old_axis_slope_angle + iang)) *
                           cot(axis_slope_angle)) + sagitta;
       return;
    }

    rang = -asin((from_index / to_index) * sin(axis_slope_angle));
    object_distance = object_distance * ((to_index * cos(-rang)) /
                      (from_index * cos(axis_slope_angle)));
    axis_slope_angle = -rang;
}

===========================================================================
                              [1mCplxTest[22m

    The CplxTest is a simple test of complex arithmetic methods.  Complex
arithmetic finds its use in many scientific and engineering fields and
some basic arithmetic using this number form is applied for this test.


typedef struct cplx {
                      double  r;
                      double  i;
                    } complex;

void CplxTest()
{
    UWORD i;
    complex c1 = { 0.243223L,1.23412L };
    complex c2 = { -0.243222L,-1.23412L };

    START_TEST_TIMER;

    for(i=0; i < 3000; i++)
    {
       c1.r = creal(c1);
       c1.i = cimg(c1);
       c2.r = -(creal(c2));
       c2.i = -(cimg(c2));

       c1 = cadd(c1,c2);
       c2 = csub(c2,c1);
       c2 = cdiv(cmul(cinv(c1),cneg(c2)) ,c1);
       c1 = cexp(conj(c2));
       c1 = ccosh(csub(c1,c2));
       c2 = cmul(cdiv(c1,c2),cdiv(c2,c1));
       c2 = cexp(cadd(conj(c2),conj(c1)));
    }

    STOP_TEST_TIMER;

    .............................................................

}

complex cadd(complex o1, complex o2)
{
   complex __aligned a1;

   a1.r = o1.r + o2.r;
   a1.i = o1.i + o2.i;
   return(a1);
}

complex csub(complex o1, complex o2)
{
   complex __aligned a1;

   a1.r = o1.r - o2.r;
   a1.i = o1.i - o2.i;
   return(a1);
}

complex cmul(complex o1, complex o2)
{
   complex __aligned a1;

   a1.r = (o1.r * o2.r) - (o1.i * o2.i);
   a1.i = (o1.r * o2.i) + (o1.i * o2.r);
   return(a1);
}

complex cinv(complex o1)
{
   double __aligned mag;
   complex __aligned a1;

   mag = (o1.r * o1.r) + (o1.i * o1.i);
   a1.r = o1.r / mag;
   a1.i = o1.i / mag;
   return(a1);
}

complex cneg(complex o1)
{
   complex __aligned a1;

   a1.r = -o1.r;
   a1.i = -o1.i;
   return(a1);
}

complex cdiv(complex o1, complex o2)
{
   return(cmul(o1,cinv(o2)));
}

complex conj(complex o1)
{
   complex __aligned a1;

   a1.r = o1.r;
   a1.i = -o1.i;
   return(a1);
}

complex cexp(complex o1)
{
   double __aligned mag;
   complex __aligned a1;

   mag = exp(o1.r);
   a1.r = mag * cos(o1.i);
   a1.i = mag * sin(o1.i);
   return(a1);
}

complex ccosh(complex o1)
{
   complex __aligned a1;

   a1 = cadd(cexp(o1),cexp(cneg(o1)));
   a1.r = 0.5 * a1.r;
   a1.i = 0.5 * a1.i;
   return(a1);
}

double creal(complex o1)
{
   return(o1.r);
}

double cimg(complex o1)
{
   return(o1.i);
}
