#include <stdio.h>
#include "resource.h"

enum {
  HOW_MANY = 20000,    /* 200 million total iterations */
  
  INT = 1,             /* integer operations */ 
  FLOAT = 2,           /* float operations */ 
  MALLOC = 3,          /* malloc and free */ 
  
  INCREMENT = 100,     /* ++ */ 
  DECREMENT = 101,     /* -- */ 
  ADD = 102,           /* + */ 
  SUBTRACT = 103,      /* - */ 
  DIVIDE = 104,        /* / */ 
};

double calculate_loop_cost( void ); 
double run_one( int datatype, int operation ); 

int main( void ) {
  double loop_cost = 0.0, operation_cost = 0.0;  

  /* Figure-out how much time it takes to do this many loops */ 
  if ( ( loop_cost = calculate_loop_cost() ) < 0 ) { 
    fprintf( stderr, "calculate_loop_cost() failed\n" ); 
    return( -1 ); 
  }

  /* Integer tests */ 
  if ( ( operation_cost = run_one( INT, ADD ) ) < 0 ) {
    fprintf( stderr, "run_one() failed\n" ); 
    return( -1 );
  } 
  fprintf( stdout, "i1 = i2 + i3\t%8.4f\n", operation_cost + (-loop_cost) ); 

  if ( ( operation_cost = run_one( INT, DIVIDE ) ) < 0 ) {
    fprintf( stderr, "run_one() failed\n" ); 
    return( -1 );
  } 
  fprintf( stdout, "i1 = i2 / i3\t%8.4f\n", operation_cost + (-loop_cost) ); 

  /* Float tests */ 
  if ( ( operation_cost = run_one( FLOAT, ADD ) ) < 0 ) {
    fprintf( stderr, "run_one() failed\n" ); 
    return( -1 );
  } 
  fprintf( stdout, "f1 = f2 + f3\t%8.4f\n", operation_cost + (-loop_cost) ); 

  if ( ( operation_cost = run_one( FLOAT, DIVIDE ) ) < 0 ) {
    fprintf( stderr, "run_one() failed\n" ); 
    return( -1 );
  } 
  fprintf( stdout, "f1 = f2 / f3\t%8.4f\n", operation_cost + (-loop_cost) ); 

  return( 0 );
}

double run_one( int datatype, int operation ) {
  struct timeval tp_start, tp_stop;
  struct rusage r_start, r_stop;
  int x = 0, y = 0, z = 0;
        
  int i1 = 1, i2 = 2, i3 = 1; 
  float f1 = 3.0, f2 = 2.0, f3 = 1.0; 
  double d1 = 3.0, d2 = 2.0, d3 = 1.0;
  
  if ( resource_start( &tp_start, &r_start ) != 0 ) {
    fprintf( stderr, "resource_start() failed\n" );
    return( -1 );
  }

  switch ( datatype ) {
    case INT:
    
      switch ( operation ) {
        case ADD:
          for ( x = 0; x < 100; x++ )
            for ( y = 0; y < 100; y++ )
              for ( z = 0; z < HOW_MANY; z++ )
                i1 = i2 + i3;
          break; 
        
        case DIVIDE:
          for ( x = 0; x < 100; x++ )
            for ( y = 0; y < 100; y++ )
              for ( z = 0; z < HOW_MANY; z++ )
                i1 = i2 / i3;
          break; 

        default:
          fprintf( stderr, "run_one(1) - illegal datatype:operation combination %d:%d\n", 
            datatype, operation ); 
          return( -1 ); 
      }
      
      break;
    
    case FLOAT:
    
      switch (operation ) {
        case ADD:
          for ( x = 0; x < 100; x++ )
            for ( y = 0; y < 100; y++ )
              for ( z = 0; z < HOW_MANY; z++ )
                f1 = f2 + f3;
          break; 

        case DIVIDE:
          for ( x = 0; x < 100; x++ )
            for ( y = 0; y < 100; y++ )
              for ( z = 0; z < HOW_MANY; z++ )
                f1 = f2 / f3;
          break; 
        
        default:
          fprintf( stderr, "run_one(2) - illegal datatype:operation combination %d:%d\n", 
            datatype, operation ); 
          return( -1 );       
      }  
      
      break; 
    
    default:
      fprintf( stderr, "run_one() - illegal datatype %d\n", datatype ); 
      return( -1 );   
  }  
                    
  if ( resource_stop( &tp_stop, &r_stop ) != 0 ) {
    fprintf( stderr, "resource_stop() failed\n" );
    return( -1 );
  }

  return ( resource_cputime( tp_start, r_start, tp_stop, r_stop ) ); 
}

double calculate_loop_cost( void ) {
  struct timeval tp_start, tp_stop;
  struct rusage r_start, r_stop;
  int x = 0, y = 0, z = 0;

  if ( resource_start( &tp_start, &r_start ) != 0 ) {
    fprintf( stderr, "resource_start() failed\n" );
    return( (double)-1 );
  }
  
  for ( x = 0; x < 100; x++ )
    for ( y = 0; y < 100; y++ )
      for ( z = 0; z < HOW_MANY; z++ )
        ; 
         	
  if ( resource_stop( &tp_stop, &r_stop ) != 0 ) {
    fprintf( stderr, "resource_stop() failed\n" );
    return( (double)-1 );
  }

  return ( resource_cputime( tp_start, r_start, tp_stop, r_stop ) ); 
}
  
