//------------------------------------------------------------
// $Id: stopwatch.h,v 1.2.2.1 2000/06/14 15:00:10 yamauchi Exp $
//------------------------------------------------------------
//
//	時間計測用のクラス By H.Yamauchi
//	using getrusage() 平成５年８月２９日(日)
//	測定結果がおかしい。考えてみるとファイルの読み込みなどを計って
//	いるので、追加した。
//	Copyright (C) 1993 YAMAUCHI Hitoshi 山内 斉
//
//	In the case of parallel processing, do not use this
//  	function(getrusage), since synchronization overhead is always
//  	ignored. 
//------------------------------------------------------------
#include <iostream.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdlib.h>
#include <assert.h>

const double MICRO_SEC_UNIT = (1/1000000.0);
const int    NOT_A_TIME     = -1;

/*
 extern "C" { 
    int getrusage(int who, struct rusage *rusage); 
 };
 */

class StopWatchClass {
protected:
    struct rusage mRusage;
    int mStartUserSec;		// sec, usecはrusageと同じ内容
    int mStartUserUsec;	// time は double で秒を保持する
    int mStartSysSec;
    int mStartSysUsec;
    int mEndUserSec;
    int mEndUserUsec;
    int mEndSysSec;
    int mEndSysUsec;
    double mStartUserTime;
    double mStartSysTime;
    double mEndUserTime;
    double mEndSysTime;

protected:
    double sec2time(int aSec, int anUsec);
    int    check_clock(void) const; // OK ... 1, other 0
    
public:
    StopWatchClass(void);
    void   start(void);		     // start 時間が initializeされる
    void   stop(void);		     // stop した時点で get を使う
    int    getUserSec(void)   const; // 何度でも stop して start した
    int    getUserUsec(void)  const; // 時点からの時間を計ることができる 
    int    getSysSec(void)   const;
    int    getSysUsec(void)  const;
    double getUser(void)   const;
    double getSystem(void) const;
    double getTotal(void)  const;
};

//
//	時間計測用のクラス By H.Yamauchi
//	using getrusage() 平成５年８月２９日(日)
//	測定結果がおかしい。考えてみるとファイルの読み込みなどを計って
//	いるので、追加した。
//
//	startしてstopすればその間の時間をgetで見れる
//
inline double StopWatchClass::sec2time(int aSec, int anUsec)
{
    return(double(aSec) + double(anUsec) * MICRO_SEC_UNIT);
}

// if OK return 1 else return 0
inline int StopWatchClass::check_clock(void) const
{
    if(this->mStartUserSec == NOT_A_TIME)
    {
	cerr << "Error! Clock has not started, yet!\n";
	return(0);
    }
    if(this->mEndUserSec   == NOT_A_TIME)
    {
	cerr << "Error! Clock is running, now\n";
	return(0);
    }
    return(1);
}

inline StopWatchClass::StopWatchClass(void)
{
    this->mStartUserSec	= NOT_A_TIME;
    this->mStartUserUsec= NOT_A_TIME;
    this->mStartSysSec	= NOT_A_TIME;
    this->mStartSysUsec	= NOT_A_TIME;
    this->mEndUserSec	= NOT_A_TIME;
    this->mEndUserUsec	= NOT_A_TIME;
    this->mEndSysSec	= NOT_A_TIME;
    this->mEndSysUsec	= NOT_A_TIME;
    this->mStartUserTime= 0.0;
    this->mStartSysTime	= 0.0;
    this->mEndUserTime	= 0.0;
    this->mEndSysTime	= 0.0;
}

    
inline void StopWatchClass::start(void)
{
    if(getrusage(RUSAGE_SELF, &this->mRusage) < 0)
    {
	cerr << "Error!(Internal::StopWatchClass) Time Infomation is invalid."
	    << endl;
	exit(1);
    }

    this->mStartUserSec	= this->mRusage.ru_utime.tv_sec;
    this->mStartUserUsec= this->mRusage.ru_utime.tv_usec;
    this->mStartSysSec	= this->mRusage.ru_stime.tv_sec;
    this->mStartSysUsec	= this->mRusage.ru_stime.tv_usec;
    this->mStartUserTime  = 
	sec2time(this->mStartUserSec, this->mStartUserUsec);
    this->mStartSysTime  = 
	sec2time(this->mStartSysSec,  this->mStartSysUsec);
}

inline void StopWatchClass::stop(void)
{
    if(getrusage(RUSAGE_SELF, &this->mRusage) < 0)
    {
	cerr << "Error!(Internal::StopWatchClass) Time Infomation is invalid."
	    << endl;
	exit(1);
    }
    this->mEndUserSec	= this->mRusage.ru_utime.tv_sec;
    this->mEndUserUsec	= this->mRusage.ru_utime.tv_usec;
    this->mEndSysSec	= this->mRusage.ru_stime.tv_sec;
    this->mEndSysUsec	= this->mRusage.ru_stime.tv_usec;
    this->mEndUserTime  = 
	sec2time(this->mEndUserSec, this->mEndUserUsec);
    this->mEndSysTime  = 
	sec2time(this->mEndSysSec,  this->mEndSysUsec);
}    

inline int StopWatchClass::getUserSec(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndUserSec - mStartUserSec);
}

inline int StopWatchClass::getUserUsec(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndUserUsec - this->mStartUserUsec);
}

inline int StopWatchClass::getSysSec(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndSysSec - mStartSysSec);
}

inline int StopWatchClass::getSysUsec(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndSysUsec - mStartSysUsec);
}

inline double StopWatchClass::getUser(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndUserTime - this->mStartUserTime);
}


inline double StopWatchClass::getSystem(void) const
{
    assert(this->check_clock() == 1);
    return(this->mEndSysTime - this->mStartSysTime);
}

inline double StopWatchClass::getTotal(void) const
{
    assert(this->check_clock() == 1);
    return((this->mEndUserTime - this->mStartUserTime) +
	   (this->mEndSysTime  - this->mStartSysTime));
}

