/*
 * 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 DISKBENCH_TIME	180
#define DISKREFTIME	0.4
#define DISKREFSCORE	415
#define MAX_CHILDS	128

#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <string.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	DISKflag,ONEflag;
extern	pid_t		child_pid[MAX_CHILDS];
extern	int		child_number;
extern	int		child;
extern	int		parent;
extern	int		cpu_score;
extern	unsigned	itim;

/*****************************************************************************/
double diskload(pmin)
unsigned pmin;
{
  double dlt;
  struct tms tmsb;
  unsigned i,j;
  void **p;
  clock_t clticks;
  clticks=times(&tmsb);
  p=(void **)malloc(pmin*sizeof(void *));
  for(i=0;i<pmin;i++)
    {
      p[i]=malloc(MUFSIZ);
      memset(p[i],i,MUFSIZ);
      if ( i%2 )
	memcpy(p[i-1],p[i],MUFSIZ);
      else
	if ( i )
	  for (j=0;j<MUFSIZ;j++)
	    ((char *)p[i-1])[j]=((char *)p[i])[j];
    }
  for(i=0;i<pmin;i++)
    free(p[i]);
  free(p);
  dlt=((double )times(&tmsb)-(double )clticks)/(double )CLK_TCK;
  return dlt;
}
/*****************************************************************************/
unsigned diskcalibrate(cdt)
double cdt;
{
  unsigned i,j;
  double dlt;
  i=1;
  while ( diskload(i) < cdt ) i*=2;
  while ( diskload(i) < cdt ) i*=2;
  j=i/4;
  do
   {
     while ( (dlt=diskload(i-j)) < cdt ) j/=2;
     i-=j;
   }
  while ( (dlt > cdt) && j );
  return i;
}
/*****************************************************************************/
int diskbench()
{
  int sv[2],i;
  int d=0;
  double dlt;
  if ( pipe(sv) == -1 )
    {
      fprintf(stderr,"****  diskbench: pipe: %s\n",sys_errlist[errno]);
      DISKflag=0;
      return 0;
    }
  cpu_score=0;
  alarm(DISKBENCH_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);
	close(sv[0]);
        dlt=(double )cpu_score*(double )itim;
        dlt=dlt/(double )DISKREFSCORE;
        cpu_score=dlt;
	fprintf(stdout,"Ubench DISK: %d\n",cpu_score);
	fflush(stdout);
        return cpu_score;
      default:
	if ( ! child )
          fprintf(stderr,"****  diskbench: exiting on signal %d\n",i);
        for (i=0;i<child_number;i++) kill(child_pid[i],SIGKILL);
        DISKflag=0;
        return 0;
    }
  itim=diskcalibrate(DISKREFTIME);
  if ( ONEflag )
    {
      dlt=itim*(double )DISKBENCH_TIME/(double )DISKREFTIME/(double )DISKREFSCORE;
      cpu_score=dlt;
      fprintf(stdout,"Ubench Single DISK: %d (%.2fs)\n",
	      cpu_score,diskload(itim));
      return cpu_score;
    }
  alarm(DISKBENCH_TIME);
  child_pid[child_number]=fork();
  if ( child_pid[child_number] == -1 )
    {
      fprintf(stderr,"****  diskbench: fork: %s\n",sys_errlist[errno]);
      DISKflag=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 ( (diskload(itim) <= DISKREFTIME) )
	    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); 
	}
    }
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1