/*
 * ubench - Unix benchmark utility
 * Copyright (C) July, 1999 Sergei Viznyuk <sv@phystech.com>
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define CPUBENCH_TIME	180
#define CPUREFTIME	0.4
#define CPUREFSCORE	50190
#define MAX_CHILDS	128

#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <time.h>

#if defined HPUX || defined _AIX
extern char *sys_errlist[];
#endif
#ifdef SunOS
extern char *_sys_errlist[];
#define sys_errlist _sys_errlist
#endif

#ifdef SunOS
extern		sigjmp_buf	env;
#else
extern		jmp_buf	env;
#endif

extern		int	CPUflag,ONEflag;
pid_t		child_pid[MAX_CHILDS];
int		child_number	=	0;
int		child		=	0;
int		parent		=	1;
int		cpu_score	=	0;
unsigned	itim		=	0;

/*****************************************************************************/
unsigned cpucalc(pmin)	/* performs rather senseless calcs */
unsigned pmin;
{
  double x,y;
  unsigned i,j,k=0;
  i=pmin;
  for (j=0;j<i;j++)
    if ( j%67 )
      k+=j%(i-j+1);
    else
      {
        x=i-j;
        y=log(1.0+x);
	x=abs(sqrt(y/(2.0+x))*(x*cos(atan(y/(3.0+x)))+y*sin(atan(y/(4.0+x)))));
	if ( x > 10.0 )
	  y=pow(1.0+j/(5.0+x),y/(6.0+x));
	else
	  y=pow(1.0+y/(1+j),x);
	x=x*exp(1.0/(1.0+y));
	k+=x;
      }
  i=k%99;
  if ( i==0 ) i++;
  return i;
}
/*****************************************************************************/
double cpuload(pmin)	/*  returns secs takes by cpucalc  */
unsigned pmin;
{
  double dlt;
  struct tms tmsb;
  clock_t clticks;
  clticks=times(&tmsb);
  if ( cpucalc(pmin) )
    dlt=((double )times(&tmsb)-(double )clticks)/(double )CLK_TCK;
  else
    dlt=0.0;
  return dlt;
}
/*****************************************************************************/
unsigned cpucalibrate(cdt)
double cdt;
{
  unsigned i,j;
  double dlt;
  i=1;
  while ( cpuload(i) < cdt ) i*=2;
  while ( cpuload(i) < cdt ) i*=2;
  j=i/4;
  do
   {
     while ( (dlt=cpuload(i-j)) < cdt ) j/=2;
     i-=j;
   }
  while ( (dlt > cdt) && j );
  return i;
}
/*****************************************************************************/
int cpubench()
{
  int sv[2],i;
  int d=0;
  double dlt;
  if ( pipe(sv) == -1 )
    {
      fprintf(stderr,"****  cpubench: pipe: %s\n",sys_errlist[errno]);
      CPUflag=0;
      return 0;
    }
  cpu_score=0;
  alarm(CPUBENCH_TIME);
  switch ( (i=sigsetjmp(env,0xffff)) )
    {
      case 0:
        break;
      case SIGALRM:
        for (i=0;i<child_number;i++) kill(child_pid[i],SIGALRM);
        if ( child ) exit(0);
        child_number=0;
	close(sv[0]);
        dlt=(double )cpu_score*(double )itim;
        dlt=dlt/(double )CPUREFSCORE;
        cpu_score=dlt;
	fprintf(stdout,"Ubench CPU: %8d\n",cpu_score);
        return cpu_score;
      default:
	if ( ! child )
          fprintf(stderr,"****  cpubench: exiting on signal %d\n",i);
        for (i=0;i<child_number;i++) kill(child_pid[i],SIGKILL);
        CPUflag=0;
        child_number=0;
        return 0;
    }
  itim=cpucalibrate(CPUREFTIME);
  if ( ONEflag )
    {
      dlt=itim*(double )CPUBENCH_TIME/(double )CPUREFTIME/(double )CPUREFSCORE;
      cpu_score=dlt;
      fprintf(stdout,"Ubench Single CPU: %8d (%.2fs)\n",
	      cpu_score,cpuload(itim));
      return cpu_score;
    }
  alarm(CPUBENCH_TIME);
  child_pid[child_number]=fork();
  if ( child_pid[child_number] == -1 )
    {
      fprintf(stderr,"****  cpubench: fork: %s\n",sys_errlist[errno]);
      CPUflag=0;
      return 0;
    }
  if ( child_pid[child_number] > 0 )
    {
      close(sv[1]);
      child_number++;
      while ( read(sv[0],&d,sizeof(d)) == sizeof(d) )
        cpu_score++;
    }
  else
    {
      close(sv[0]);
      child=1;
      while ( 1 )
	{
	  if ( (cpuload(itim) <= CPUREFTIME) )
	    if ( parent && (child_number < MAX_CHILDS ) )
	      {
	        child_pid[child_number]=fork();
	        if ( child_pid[child_number] > 0 )
		  child_number++;
	        else
		  {
		    parent=0;
		    d++;
		    continue;
		  }
	      }
	  if ( write(sv[1],&d,sizeof(d)) != sizeof(d) ) exit(0); 
	}
    }
  child_number=0;
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1