//------------------------------------------------------------
// $Id: ElapsedTimer.h,v 1.1.1.1 1999/11/25 06:26:11 yamauchi Exp $
//------------------------------------------------------------
//	時間計測用のクラス
//	using gettimeofday() 1999年4月 5日(月)
//	
//	以前は getrusage を使っていたが，並列計算には向かない．という
//	のは，ある process が通信待ちで停止すると sleep に入ってしまい，
//	通信の overhead が測定できなくなってしまうからである．それは並
//	列計算の場合には良い測定基準とは言えない． 
//	
//	Copyright (C) 1999 YAMAUCHI Hitoshi 山内 斉
//------------------------------------------------------------
/**
 * 利用法
 *	ElapsedTimerClass et;
 *      et.start();
 *      do_something();	// 計りたい関数を囲む
 *	et.stop();
 *	cout << "Elapsed time = " << et.getTotalTime() << " sec" << endl;
 * これで経過時間がわかる．
 */

#ifndef _ElapsedTimer_h
#define _ElapsedTimer_h 1

#include <assert.h>
#include <iostream.h>
#include <sys/time.h>

const int ElapsedTimerClass_NOT_A_TIME     = -1;

class ElapsedTimerClass {
protected:
    struct timeval mStartTimeVal; // 開始時刻
    struct timeval mStopTimeVal;  // stop した時刻
    
public:
    ElapsedTimerClass(void)
    {
	struct timeval notatime_tv;	
	notatime_tv.tv_sec  = ElapsedTimerClass_NOT_A_TIME;
	notatime_tv.tv_usec = ElapsedTimerClass_NOT_A_TIME;

	this->mStartTimeVal = notatime_tv;
	this->mStopTimeVal  = notatime_tv;
    }
    ElapsedTimerClass(const ElapsedTimerClass& rhs)
    {
	this->mStartTimeVal = rhs.mStartTimeVal;
	this->mStopTimeVal  = rhs.mStopTimeVal;
    }
    const ElapsedTimerClass& operator=(const ElapsedTimerClass& rhs)
    {
	if(this != &rhs)
	{
	    this->mStartTimeVal = rhs.mStartTimeVal;
	    this->mStopTimeVal  = rhs.mStopTimeVal;
	}
	return(*this);
    }

    // 開始時刻クリア
    void reset(void)
    {
	this->mStartTimeVal.tv_sec  = ElapsedTimerClass_NOT_A_TIME;
	this->mStartTimeVal.tv_usec = ElapsedTimerClass_NOT_A_TIME;
    }

    // 時間測定開始
    void start(void)
    {
	gettimeofday(&(this->mStartTimeVal), NULL);
    }

    // 時間測定終了 : stop は何度でも call できる．その都度 start から
    // の時間が getTotalTime で取り出せる
    void stop(void)
    {
	gettimeofday(&(this->mStopTimeVal), NULL);	
    }

    // 時間総計を返す
    double getTotalTime(void) const
    {
	// start と stop は既に呼ばれている
	assert((this->mStartTimeVal.tv_sec  != ElapsedTimerClass_NOT_A_TIME)&& 
	       (this->mStartTimeVal.tv_usec != ElapsedTimerClass_NOT_A_TIME));
	assert((this->mStopTimeVal.tv_sec   != ElapsedTimerClass_NOT_A_TIME)&& 
	       (this->mStopTimeVal.tv_usec  != ElapsedTimerClass_NOT_A_TIME));

	const double MICRO_SEC_FACT = 1000000.0;	

	// s ... second, us ... micro second
	long int s  = this->mStopTimeVal.tv_sec  - this->mStartTimeVal.tv_sec;
	long int us = this->mStopTimeVal.tv_usec - this->mStartTimeVal.tv_usec;

	double ret = ((double)(s)) + ((double)(us)) / MICRO_SEC_FACT;	
	return(ret);
    }

    // 秒のみを long int で返す
    long int getSecondTime(void) const 
    {
	assert((this->mStartTimeVal.tv_sec  != ElapsedTimerClass_NOT_A_TIME)&& 
	       (this->mStartTimeVal.tv_usec != ElapsedTimerClass_NOT_A_TIME));
	assert((this->mStopTimeVal.tv_sec   != ElapsedTimerClass_NOT_A_TIME)&& 
	       (this->mStopTimeVal.tv_usec  != ElapsedTimerClass_NOT_A_TIME));
	
	// s ... second, us ... micro second
	long int s  = this->mStopTimeVal.tv_sec  - this->mStartTimeVal.tv_sec;
	return(s);
    }

    // 生の時間を返す
    static double getNowRawTime(void) 
    {
	const double MICRO_SEC_FACT = 1000000.0;	
	struct timeval tp;
	gettimeofday(&tp, NULL);
	double ret = ((double)(tp.tv_sec)) + 
		     ((double)(tp.tv_usec)) / MICRO_SEC_FACT;
	return(ret);	
    }
    static long int getNowRawTimeAsSecond(void) 
    {
	struct timeval tp;
	gettimeofday(&tp, NULL);
	return(tp.tv_sec);	
    }
};

#endif				// #ifndef _ElapsedTimer_h
