/*
 * $Id: ElapsedTimer.java,v 1.4 1999/11/29 18:38:06 yamauchi Exp $
 *     (M\pi)^2 : Elapsed Timer 
 *	Copyright 1999 By YAMAUCHI Hitoshi 山内 斉 
 *	@author YAMAUCHI Hitoshi 山内 斉
 *
 *	時間計測用のクラス
 *	以前は getrusage を使っていたが，並列計算には向かない．という
 *	のは，ある process が通信待ちで停止すると sleep に入ってしまい，
 *	通信の overhead が測定できなくなってしまうからである．それは並
 *	列計算の場合には良い測定基準とは言えない． 
 *
 * class StopWatch (getrusage を使用していた) は Java 化に伴い廃止
 *
 * original source ElapsedTimer.h
 *
 * 1999年8月17日(火)
 */

package jp.ac.tohoku.is.archi.mpi2.util;

import  jp.ac.tohoku.is.archi.mpi2.sysparam.*;

/**
 * ElapsedTimer : 時間計測のためのクラス
 */
public final class ElapsedTimer {
    public final int ElapsedTimer_NOT_A_TIME     = -1;

    private long mStartTimeVal; // 開始時刻
    private long mStopTimeVal;  // 停止した時刻
    
    
    public ElapsedTimer()
    {
	this.mStartTimeVal = ElapsedTimer_NOT_A_TIME;
	this.mStopTimeVal  = ElapsedTimer_NOT_A_TIME;
    }

    public ElapsedTimer(ElapsedTimer rhs)
    {
	this.mStartTimeVal = rhs.mStartTimeVal;
	this.mStopTimeVal  = rhs.mStopTimeVal;
    }

    /**
     * 開始時刻クリア : clear time
     */ 
    public void reset()
    {
	this.mStartTimeVal = ElapsedTimer_NOT_A_TIME;
	this.mStartTimeVal = ElapsedTimer_NOT_A_TIME;
    }

    /**
     * 時間測定開始 : set start time
     */
    public void start()
    {
	this.mStartTimeVal = System.currentTimeMillis();
    }

    /**
     * 時間測定終了 : stop は何度でも call できる．その都度 start から
     * の時間が getTotalTime で取り出せる
     */
    public void stop()
    {
	this.mStopTimeVal = System.currentTimeMillis();
    }

    /**
     * 時間測定可能な状態か? : start と stop は呼ばれているか
     */
    private void isOK()
    {
	// start と stop は既に呼ばれている
	if(this.mStartTimeVal == ElapsedTimer_NOT_A_TIME)
	{
	    throw new RuntimeException("Error! : ElapsedTimer.getTotalTime " +
				       "must call after start() call.");
	}	    
	if(this.mStopTimeVal  == ElapsedTimer_NOT_A_TIME)
	{
	    throw new RuntimeException("Error! : ElapsedTimer.getTotalTime " +
				       "must call after stop() call.");
	}	    
    }

    // 時間総計を返す
    public long getTotalTime() 
    {
	this.isOK();
	return(this.mStopTimeVal - this.mStartTimeVal);
    }

    // 秒のみを long int で返す
    public long getSecondTime() 
    {
	this.isOK();
	long s = (this.mStopTimeVal - this.mStartTimeVal) / 1000;
	return(s);
    }

    /**
     * 生の milisec 時間を返す
     */
    public static long getNowRawTime() 
    {
	return(System.currentTimeMillis());
    }

    /**
     * 生の sec 時間を返す
     */
    public static long getNowRawTimeAsSecond() 
    {
	return(System.currentTimeMillis() / 1000);
    }

    /**
     * output elapsed time of PE
     */
    public static void outPEEtime(String mes, ElapsedTimer etimer)
    {
	String s = Mpi2Constants.NORMALHEAD + " PE:: elapsed time " + 
	    etimer.getTotalTime() + " (msec) " + mes;
	System.out.println(s);
    }

    /**
     * output nowtime value of PE 
     */
    public static void outPERawTime(String mes)
    {
	String s = Mpi2Constants.NORMALHEAD + " PE:: raw time " + 
	    ElapsedTimer.getNowRawTime() + " (msec) " + mes;
	System.out.println(s);
    }

    /**
     * Host での経過時間の出力
     */
    public static void outHostEtime(String mes, ElapsedTimer etimer)
    {
	String s = Mpi2Constants.NORMALHEAD + " host:: elapsed time " + 
	    etimer.getTotalTime() + " (msec) " + mes;
	System.out.println(s);
    }

    /**
     * Host の現在時刻をメッセージ付きで出力する
     */
    public static void outHostRawTime(String mes)
    {
	String s = Mpi2Constants.NORMALHEAD + " host:: raw time " + 
	    ElapsedTimer.getNowRawTime() + " (msec) " + mes;
	System.out.println(s);	
    }

    /**
     * test 
     */
    public static void main(String [] args)
    {
	ElapsedTimer et = new ElapsedTimer();
	et.start();
	// 計りたい関数を囲む
	System.out.println("Now time = " + ElapsedTimer.getNowRawTime());
	et.stop();
	System.out.println("Elapsed time = " + et.getTotalTime() + " msec");
    }
}
