/* This is the include file containing the code
   for the tests of the Amiga version.
*/

/****** posbb_tests.c/--background-- ***************************************
*
*     These are the functions wich really do tests. All them returns
*     the time taken in seconds. In future version they will able to
*     return a more accurate value (with some decimal)
*
****************************************************************************
*/



#include <stdio.h>
#include <stdlib.h>
#include <dos/dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <math.h>





/* Define NOFORBID if compiling ofr PowerUp or other Amiga-like sistems lacking Forbid()/Permit() */





/****** posbb_tests.c/Test_CopyMem ******************************************
*
*   NAME
*     Test_CopyMem -- Tests speed of exec.library/CopyMem().
*
*   SYNOPSIS
*     time = Test_CopyMem( int precision )
*
*     int Test_CopyMem( int );
*
*   FUNCTION
*     Does 100,000 CopyMem() of a 1024 bytes memory block and returns the
*     time it has spent.
*
*   INPUT
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*
*   RESULT
*     time - Time spent,in seconds.
*            TRUE if something went wrong (usually lack of memory).
*
*   EXAMPLE
*     Examine posbb.c/Perform_Tests().
*
*   BUGS
*     It has no known bugs,but it use if (freeze == TRUE) Forbid() and if (freeze == TRUE) Permit(),
*     also if Amiga Technologies has told not to use them for future
*     compatibility.If the AmigaOS will really ported to PowerPC processor
*     and this will not work,I'll fix it.
****************************************************************************
*/

int Test_CopyMem( precision, freeze )
int precision;
int freeze;
{
   struct timeval *time1,*time2;
   long mem1,mem2;
   int c,time;
   time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
   time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

   if (mem1=AllocMem(1024,0))
   {
     if (mem2=AllocMem(1024,0))
     {
#ifndef NOFORBID
	if (freeze == TRUE) Forbid(); /* This turns off multitasking */
#endif
	GetSysTime(time1);
	for ( c = 0; c<100000; c++ )
	{
	  CopyMem(mem1,mem2,1024);
	}
	GetSysTime(time2);
#ifndef NOFORBID
	if (freeze == TRUE) Permit(); /* This turns on multitasking    */
#endif
	FreeMem(mem1,1024);
	FreeMem(mem2,1024);
     }
     else return TRUE;
   }
   else return TRUE;
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  return time;
}


/****** posbb_tests.c/Test_printf ******************************************
*
*   NAME
*     Test_printf -- Tests the speed of the ANSI function printf().
*
*   SYNOPSIS
*     time = Test_printf( int precision )
*     int Test_printf( int );
*
*   FUNCTION
*     Writes 1,000 times the string "printf test in progress...\n" to stdout
*     and returns the time taken.
*
*   INPUT
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*
*   RESULT
*     time - number of seconds spent.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests().
*
*   NOTE
*     In future versions it will return a float.
*
*   BUGS
*     It hasn't bugs,but since it can't turn off multitasking,the result
*     could change if the user runs some program or move windows.
*
****************************************************************************
*/
int Test_printf( precision , freeze)
int precision;
int freeze;
{
  int c,time;
  struct timeval *time1,*time2;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for ( c = 0; c<1000*precision; c++ )
  {
    printf("printf test in progress...\n");
  }
  GetSysTime(time2);
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  return time;

}

/****** posbb_tests.c/Test_IMath ********************************************
*
*   NAME
*     Test_IMath -- Tests the speed of some int Math operations.
*
*   SYNOPSIS
*     time = Test_IMath( int precision )
*     int Test_IMath( int );
*
*   FUNCTION
*     Does 1 million of additions,differences,multiplications and divisions
*     and returns the time it took.
*
*   INPUT
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent in seconds. No error can be returned.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests()
*
*   BUGS
*
*     Like some other function it uses if (freeze == TRUE) Forbid()/if (freeze == TRUE) Permit(),wich probably will
*     not work under a future Amiga OS.
*     It doesn't check if memory allocations fail. In that case it will
*     probably crash. I'll fix it in future versions.
*
****************************************************************************
*/

int Test_IMath( precision,freeze )
int precision;
int freeze;
{
  int c,i=0,time;
  long *a=0,*b=0,*d=0;
  struct timeval *time1,*time2;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

  a = calloc(sizeof(long),100*precision);
  b = calloc(sizeof(long),100*precision);
  d = calloc(sizeof(long),100*precision);
  /* Initializing b and d table with random values */
  for(i =0;i<(100*precision);i++)
  {
    b[i] = rand();
    d[i] = rand();
  }
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for (c = 0;c<10000;c++)
  {
    for ( i = 0; i<(100 * precision)-3; i+=3 )
    {
      a[i] /= b[i] + d[i];
      a[i+1] *= b[i+1] - d[i+1];
      a[i+2] += b[i+2] * d[i+2];
      a[i+3] -= b[i+3] / d[i+3];
    }
  }
  GetSysTime(time2);
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  free(a);
  free(b);
  free(d);
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  return time;
}

/****** posbb_tests.c/Test_FPMath ********************************************
*
*   NAME
*     Test_FPMath -- Tests the speed of some floating point Math operations.
*
*   SYNOPSIS
*     time = Test_FPMath( int precision )
*     int Test_FPMath( int );
*
*   FUNCTION
*     Does 1 million of additions,differences,multiplications and divisions
*     and returns the time it took.
*
*   INPUT
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent in seconds. At the moment no error can be returned.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests()
*
*   NOTES
*     To obtain code for FPU use the right option of your compiler.
*
*   BUGS
*     Like some other functions it uses if (freeze == TRUE) Forbid()/if (freeze == TRUE) Permit(),wich probably will
*     not work under a future Amiga OS.
*     Until now it doesn't check if memory allocations needed for variuos
*     tables used in the test has failed. In that case it will probably
*     crash. I'll fix it in new versions.
*
****************************************************************************
*/


int Test_FPMath( precision ,freeze )
int precision;
int freeze;
{
  int c,i=0,time;
  double *a=0,*b,*d;
  struct timeval *time1,*time2;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

  a = calloc(sizeof(double),100*precision);
  b = calloc(sizeof(double),100*precision);
  d = calloc(sizeof(double),100*precision);
  /* Initializing b and d table with random values; */
  for(c =0;c<(100*precision);c++) {
    b[c] = (double) rand();
    d[c] = (double) rand();
  }
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for (c = 0;c<10000;c++)
  {
    for ( i = 0; i<(100 * precision)-3; i+=3 )
    {
      a[i] /= b[i] + d[i];
      a[i+1] *= b[i+1] - d[i+1];
      a[i+2] += b[i+2] * d[i+2];
      a[i+3] -= b[i+3] / d[i+3];
    }
  }
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  GetSysTime(time2);
  free(a);
  free(b);
  free(d);
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));

  return time;

}


/****** posbb_tests.c/Test_Write ********************************************
*
*   NAME
*     Test_Write -- Tests disk writing speed.
*
*   SYNOPSIS
*     time = Test_Write( STRPTR filename,int precision )
*     double Test_Write( STRPTR ,int );
*
*   FUNCTION
*     Writes a block of data to a file,with dos.library/Write() (in the Amiga
*     version).
*
*   INPUT
*     STRPTR filename   the name of the file to write to.
*
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent ins econds.
*            Returns TRUE if something went wrong ( memory or disk space usually).
*            In future may return differents error codes.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests.
*
*   BUGS
*     No known bugs.
*
****************************************************************************
*/

int Test_Write(STRPTR filename,BOOL freeze)

{
  struct timeval *time1,*time2;
  long buf;
  int c,time;
  BPTR file;

  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

  if ( buf=AllocMem(262144,0))
  {
    if (file = (BPTR) Open(filename,MODE_NEWFILE))
    {
#ifndef NOFORBID
      if (freeze == TRUE) Forbid();
#endif
      GetSysTime(time1);
      for (c = 0;c<20;c++ )
      {
      Write(file,buf,262144);
      }
      GetSysTime(time2);
#ifndef NOFORBID
      if (freeze == TRUE) Permit();
#endif
      FreeMem(buf,262144);
      Close(file);
    }
  }
  else return TRUE;
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));

  if (file=(BPTR) 0) return TRUE;
  else return time;
}

/****** posbb_tests.c/Test_Read ********************************************
*
*   NAME
*     Test_Read -- Tests disk reading speed.
*
*   SYNOPSIS
*     time = Test_Read( STRPTR filename,int precision )
*     int Test_Read( STRPTR, int );
*
*   FUNCTION
*     Reades a block of data from a file,with dos.library/Read() (in the
*     Amiga version).
*
*   INPUT
*     STRPTR filename   the name of the file to read from
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent in seconds.
*            Returns TRUE if something went wrong ( memory or disk space
*            usually). In future may return differents error codes.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests.
*
*   NOTES
*     In future versions it will use different functions depending on dos.library version.
*     With dos.library V 36+ it will use buffered routines,unbuffered on previous versions.
*     The results given by Test_Read() and Test_Write() depend not only on the disk/filesystem
*     speed, but also on disk fragmentation. For a more reliable test of your HD use
*     other programs.
*.
*   BUGS
*     No known bugs.
*
****************************************************************************
*/



int Test_Read(STRPTR filename,BOOL freeze)
{
  struct timeval *time1,*time2;
  long buf;
  int c,time;
  BPTR file=(BPTR) 0;

  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

  if ( buf = AllocMem(262144,0))
  {
    if (file = (BPTR) Open(filename,MODE_OLDFILE))
    {
#ifndef NOFORBID
      if (freeze == TRUE) Forbid();
#endif
      GetSysTime(time1);
      for (c=0;c<20;c++)
      {
      Read(file,buf,262144);
      }
      GetSysTime(time2);
#ifndef NOFORBID
      if (freeze == TRUE) Permit();
#endif
      Close(file);
    }
    FreeMem(buf,262144);
  }
  else return TRUE;
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  if (file = (BPTR) 0) return TRUE;
  else return time;
}



/****** posbb_tests.c/Test_WritePixel ********************************************
*
*   NAME
*     Test_WritePixel -- Tests pixel writing speed.
*
*   SYNOPSIS
*     time = Test_WritePixel(struct RastPort *rport,int precision)
*     int Test_WritePixel( struct RastPort,int );
*
*   FUNCTION
*     Fill the given rastport pixel by pixel with graphics.library/WritePixel()
*     and returns the time taken.
*
*   INPUT
*     *rport            pointer to a valid RastPort structure to draw on.
*
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent in seconds. No errors can be returned.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests.
*
*   BUGS
*     No known bugs.
*
****************************************************************************
*/



int Test_WritePixel( rport,precision,freeze)
struct RastPort *rport;
int precision;
int freeze;
{
  struct timeval *time1,*time2;
  int x,y,pen,time;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for (pen=0;pen<4*precision;pen++)
  {
     SetAPen(rport,pen);
     for (y=0;y<255;y++)
     {
	for (x=0;x<319;x++)
	{
	   WritePixel(rport,x,y);
	}
     }
  }
  GetSysTime(time2);
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  SubTime(time2,time1);
  time = (time2->tv_secs);
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  return time;
}

/****** posbb_tests.c/Test_DrawEllipse ********************************************
*
*   NAME
*     Test_DrawEllipse -- Tests pixel ellipse drawing speed.
*
*   SYNOPSIS
*     time = Test_DrawEllipse(struct RastPort *rport,int precision)
*     int Test_DrawEllipse( struct RastPort,int );
*
*   FUNCTION
*     Draws some ellipses in the given rastport and returns the time taken.
*
*
*   INPUT
*     struct RastPort *rport    pointer to a valid RastPort structure
*
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent in seconds. No error can be returned.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests.
*
*   BUGS
*     No known bugs.
*
****************************************************************************
*/

int Test_DrawEllipse(rport,precision,freeze)
struct RastPort *rport;
int precision;
int freeze;
{
  struct timeval *time1,*time2;
  short a,b,pen;
  int time;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for (pen=0;pen<4*precision;pen++)
  {
    SetAPen(rport,pen);
    for (a=1;a<159;a++)
    {
      b = ((a * 256) / 320);
      DrawEllipse(rport,159,127,a,b);
    }
   }
   GetSysTime(time2);
#ifndef NOFORBID
   if (freeze == TRUE) Permit();
#endif
   SubTime(time2,time1);
   time = time2->tv_secs;
   FreeMem(time1,sizeof(struct timeval));
   FreeMem(time2,sizeof(struct timeval));
   return time;
}

/****** posbb_tests.c/Test_Draw ***********************************************
*
*   NAME
*     Test_Draw -- Tests pixel ellipse drawing speed.
*
*   SYNOPSIS
*     time = Test_Draw(struct RastPort *rport,int precision)
*     int Test_Draw( struct RastPort,int );
*
*   FUNCTION
*     Draws some lines in the given rastport and returns the time taken.
*
*
*   INPUT
*     struct RastPort *rport  Pointer to a valid RastPort structure to draw on.
*
*     int precision     the precision of the results. Can be any of
*                       POSBB_PREECISION#?. The higher is the precision wanted,
*                       the higher the time taken. precision is useful on faster
*                       machines,on wich the times will be too low.
*
*   RESULT
*     time - Time spent,in seconds.
*
*   EXAMPLE
*     See posbb.c/Perform_Tests.
*
*   BUGS
*     No known bugs.
*
****************************************************************************
*/


int Test_Draw(rport,precision,freeze)
struct RastPort *rport;
int precision;
int freeze;
{
  struct timeval *time1,*time2;
  short x,y,x1,y1,pen;
  int time;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  Move(rport,0,0);
  for(pen=0;pen<4*precision;pen++)
  {
    SetAPen(rport,pen);
    for (y=0;y<256;y++)
    {
      Draw(rport,320,y);
      Move(rport,0,0);
    }
    for (x=0;x<320;x++)
    {
      Draw(rport,x,256);
      Move(rport,0,0);
    }
    SetAPen(rport,pen-1);
    for(y=0;y<256;y++)
    {
      Draw(rport,320,y);
      Draw(rport,0,y+1);
    }
  }
  GetSysTime(time2);
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));
  
  return time;
}

/* qsort isn't finished,yet

int my_comp(s1,s2)
char **s1,**s2;
{
   return(strcmp(*s1, *s2));
}

int Test_qsort(precision)
int precision;
{
int c;
  struct timeval *time1,*time2;
  if (freeze == TRUE) Forbid();
  GetSysTime(time1);
  for(c = 0;c<100*precision;c++){
  qsort(StrList,1000,sizeof(char *),my_comp);
  }
  GetSysTime(time2);
  if (freeze == TRUE) Permit();
  return (time2->tv_secs);
}

*/


int Test_TMath(precision,freeze)
int precision;
int freeze;
{
  struct timeval *time1,*time2;
  int c=0,time;
  double *cosine=0,*sine=0,*tangent=0,angle = 0;
  time1 = (struct timeval *) AllocMem(sizeof(struct timeval),0);
  time2 = (struct timeval *) AllocMem(sizeof(struct timeval),0);

  cosine = calloc(sizeof(double),360*precision);
  sine = calloc(sizeof(double),360*precision);
  tangent = calloc(sizeof(double),360*precision);
#ifndef NOFORBID
  if (freeze == TRUE) Forbid();
#endif
  GetSysTime(time1);
  for(c=0;c<100;c++){
    for(angle=0;angle<360*precision;angle++)
    {
      sine[(int)angle] = sin(angle);
      cosine[(int)angle] = cos(angle);
      tangent[(int)angle] = tan(angle);
    }
  }
  GetSysTime(time2);
#ifndef NOFORBID
  if (freeze == TRUE) Permit();
#endif
  free(sine);
  free(cosine);
  free(tangent);
  SubTime(time2,time1);
  time = time2->tv_secs;
  FreeMem(time1,sizeof(struct timeval));
  FreeMem(time2,sizeof(struct timeval));

  return (time);
}



