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

int resource_start( struct timeval *tp_start, struct rusage *r_start ) {

  if ( gettimeofday( tp_start, NULL ) != 0 ) { 
    perror( "gettimeofday() failed" );
    return( -1 );
  }

  if ( getrusage( RUSAGE_SELF, r_start ) != 0 ) {
    perror( "getrusage() failed" );
    return( -1 );
  }
  
  return( 0 ); 
}

int resource_stop( struct timeval *tp_stop, struct rusage *r_stop ) {

  if ( gettimeofday( tp_stop, NULL ) != 0 ) { 
    perror( "gettimeofday() failed" );
    return( -1 );
  }

  if ( getrusage( RUSAGE_SELF, r_stop ) != 0 ) {
    perror( "getrusage() failed" );
    return( -1 );
  }

  return( 0 ); 
}

void resource_display_delta( struct timeval tp_start, struct rusage r_start, 
                             struct timeval tp_stop, struct rusage r_stop, char label[] ) {
  double wtime;      /* wall time */
  double utime;      /* user CPU time */ 
  double stime;      /* system CPU time */ 
 
  long maxrss;       /* maximum resident set size */
  long ixrss;        /* integral shared memory size */
  long idrss;        /* integral unshared data size */
  long isrss;        /* integral unshared stack size */
  long minflt;       /* page reclaims or soft faults */
  long majflt;       /* page faults or hard faults */

  long nswap;        /* swaps */
  
  long inblock;      /* block input operations */
  long oublock;      /* block output operations */

  long msgsnd;       /* messages sent */
  long msgrcv;       /* messages received */
  long nsignals;     /* signals received */
 
  long nvcsw;        /* voluntary context switches */
  long nivcsw;       /* involuntary context switches */ 
  
  /* xxx - how to check the time resolution from the system include files? */ 
  
  wtime = (double)( tp_stop.tv_sec - tp_start.tv_sec ) + 
          (double)(( tp_stop.tv_usec - tp_start.tv_usec ) * 
            (double)0.000001 );
            
  utime = (double)(r_stop.ru_utime.tv_sec - r_start.ru_utime.tv_sec )  +
          (double)(( r_stop.ru_utime.tv_usec - r_start.ru_utime.tv_usec ) * 
            (double)0.000001 ); 

  stime = (double)(r_stop.ru_stime.tv_sec - r_start.ru_stime.tv_sec )  +
          (double)(( r_stop.ru_stime.tv_usec - r_start.ru_stime.tv_usec ) * 
            (double)0.000001 );

  maxrss = r_stop.ru_maxrss; 
  ixrss = r_stop.ru_ixrss; 
  idrss = r_stop.ru_idrss;
  isrss = r_stop.ru_isrss; 
  minflt = r_stop.ru_minflt - r_start.ru_minflt; 
  majflt = r_stop.ru_majflt - r_start.ru_majflt; 
  
  nswap = r_stop.ru_nswap - r_start.ru_nswap; 

  inblock = r_stop.ru_inblock - r_start.ru_inblock; 
  oublock = r_stop.ru_oublock - r_start.ru_oublock; 
  
  msgsnd = r_stop.ru_msgsnd - r_start.ru_msgsnd; 
  msgrcv = r_stop.ru_msgrcv - r_start.ru_msgrcv; 
  nsignals = r_stop.ru_nsignals - r_start.ru_nsignals; 
  
  nvcsw = r_stop.ru_nvcsw - r_start.ru_nvcsw; 
  nivcsw = r_stop.ru_nivcsw - r_start.ru_nivcsw; 
  
  fprintf( stdout, "%s\tcputime=%8.4f\n", label, utime + stime );  
  
/*  fprintf( stderr, "%s wtime=%.4f utime=%.4f stime=%.4f maxrss=%d ixrss=%d idrss=%d isrss=%d minflt=%d majflt=%d nswap=%d inblock=%d outblock=%d msgsnd=%d msgrcv=%d nsignals=%d nvcsw=%d nivcsw=%d\n", 
    label, wtime, utime, stime, maxrss, ixrss, idrss, isrss, minflt, majflt, 
    nswap, inblock, oublock, msgsnd, msgrcv, nsignals, nvcsw, nivcsw ); */ 
    
  return; 
}

double resource_cputime( struct timeval tp_start, struct rusage r_start, 
                         struct timeval tp_stop, struct rusage r_stop ) {
  double utime;      /* user CPU time */ 
  double stime;      /* system CPU time */ 
   
  /* xxx - how to check the time resolution from the system include files? */ 
  
  utime = (double)(r_stop.ru_utime.tv_sec - r_start.ru_utime.tv_sec )  +
          (double)(( r_stop.ru_utime.tv_usec - r_start.ru_utime.tv_usec ) * 
            (double)0.000001 ); 

  stime = (double)(r_stop.ru_stime.tv_sec - r_start.ru_stime.tv_sec )  +
          (double)(( r_stop.ru_stime.tv_usec - r_start.ru_stime.tv_usec ) * 
            (double)0.000001 );

  return ( utime + stime ); 
}
