/*====================================================================
 *
 * FILE:
 * testtimer.c
 *
 * IDENTIFICATION:
 * $Header: /private/postgres/src/test/RCS/testtimer.c,v 1.2 1990/08/18 16:10:48 sp Exp $
 *
 * These are some routines that can be used to time postgres.
 *
 * initTimer():
 *	Initialize the timer. The timer starts running...
 *	(can be called more than once...)
 *
 * double getTimer():
 *	get the number of ellapsed seconds since `initTimer()'
 *
 * stopTimer():
 *      stop temporarily the timer
 *
 * restartTimer():
 *	restart the timer after a 'stopTimer()' call.
 * 
 *
 *
 *====================================================================
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>

/* #define DEBUG */
#define MILLION		1000000L

static void zeroTimeVal();
static void copyTimeVal();
static void addTimeVal();
static void subTimeVal();
static void getTimeVal();
static double timeValToDouble();
static void printTimeVal();

static int TimerIsRunning = 0;
static struct timeval StartTimeVal;
static struct timeval ElapsedTimeSinceStop;

/*----------------------------------------------------
 *
 * zeroTimeVal
 *
 */
static
void
zeroTimeVal(x)
struct timeval *x;
{
    x->tv_sec = 0L;
    x->tv_usec = 0L;
}
/*----------------------------------------------------
 *
 * copyTimeVal
 *
 */
static
void copyTimeVal(src, dest)
struct timeval src;
struct timeval *dest;
{
    dest->tv_sec = src.tv_sec;
    dest->tv_usec = src.tv_usec;
}

/*----------------------------------------------------
 *
 * addTimeVal
 *
 * add 2 timeval structs.
 */
static
void
addTimeVal(v1, v2, res)
struct timeval v1;
struct timeval v2;
struct timeval *res;
{
    long usecs;

#ifdef DEBUG
    printf("addTimeVal: ");
    printTimeVal(v1); printf("+"); printTimeVal(v2); printf("=");
#endif DEBUG

    usecs = v1.tv_usec + v2.tv_usec;
    res->tv_usec = usecs % MILLION;
    res->tv_sec = v1.tv_sec + v2.tv_sec + usecs/MILLION;

#ifdef DEBUG
    printTimeVal(*res); printf("\n");
#endif DEBUG
}

/*----------------------------------------------------
 *
 * subTimeVal
 *
 * subtract 2 timeval structs.
 */
static
void
subTimeVal(v1, v2, res)
struct timeval v1;
struct timeval v2;
struct timeval *res;
{
    long borrow;

#ifdef DEBUG
    printf("subTimeVal: ");
    printTimeVal(v1); printf("-"); printTimeVal(v2); printf("=");
#endif DEBUG

    if (v1.tv_usec >= v2.tv_usec)  {
	res->tv_usec = v1.tv_usec - v2.tv_usec;
	borrow = 0L;
    } else {
	res->tv_usec = v1.tv_usec - v2.tv_usec + MILLION;
	borrow = 1L;
    }
    res->tv_sec = v1.tv_sec - v2.tv_sec - borrow;

#ifdef DEBUG
    printTimeVal(*res); printf("\n");
#endif DEBUG
}

/*------------------------------------------------------
 *
 * getTimeVal
 *
 */
static
void
getTimeVal(res)
struct timeval *res;
{
    struct rusage x, y;
    struct timeval self, children;

#ifdef DEBUG
    printf("getTimeVal----in\n");
#endif DEBUG

    getrusage(RUSAGE_SELF, &x);
    getrusage(RUSAGE_CHILDREN, &y);

    addTimeVal(x.ru_utime, x.ru_stime, &self);
    addTimeVal(y.ru_utime, y.ru_stime, &children);
    addTimeVal(self, children, res);

#ifdef DEBUG
    printf("getTimeVal----out, res:");
    printTimeVal(*res); printf("\n");
#endif DEBUG
}

/*------------------------------------------------------
 *
 * timeValToDouble
 */
static
double
timeValToDouble(t)
struct timeval t;
{
    double res;

    res = (double) t.tv_sec + ((double) t.tv_usec) / ((double)MILLION);
#ifdef DEBUG
    printf("timeValToDouble: struct=");
    printTimeVal(t); printf(", double=%.6f\n", res);
#endif DEBUG

    return(res);
}

/*------------------------------------------------------
 *
 * printTimeVal
 */
static
void
printTimeVal(t)
struct timeval t;
{
    printf("[%ld,%ld]", t.tv_sec, t.tv_usec);
}

/*------------------------------------------------------
 *
 * initTimer
 *
 */
initTimer()
{
#ifdef DEBUG
    printf("initTimer--------in\n");
#endif DEBUG
    getTimeVal(&StartTimeVal);
    zeroTimeVal(&ElapsedTimeSinceStop);
    TimerIsRunning = 1;
#ifdef DEBUG
    printf("initTimer--------out\n");
#endif DEBUG
}

/*------------------------------------------------------
 *
 * getTimer
 *
 */
double
getTimer()
{
    struct timeval now, res;
    double d;

#ifdef DEBUG
    printf("getTimer--------in\n");
#endif DEBUG

    if (TimerIsRunning) {
	getTimeVal(&now);
	subTimeVal(now, StartTimeVal, &res);
	addTimeVal(ElapsedTimeSinceStop, res, &res);
    } else {
	copyTimeVal(ElapsedTimeSinceStop, &res);
    }

    d = timeValToDouble(res);

#ifdef DEBUG
    printf("getTimer--------out, ret=%.6f\n", d);
#endif DEBUG

    return(d);
}

/*------------------------------------------------------
 *
 * stopTimer
 *
 */
stopTimer()
{
    struct timeval now, interval;

    getTimeVal(&now);
    TimerIsRunning = 0;
    subTimeVal(now, StartTimeVal, &interval);
    addTimeVal(ElapsedTimeSinceStop, interval, &ElapsedTimeSinceStop);
}

/*------------------------------------------------------
 *
 * restartTimer
 *
 */
restartTimer()
{
    getTimeVal(&StartTimeVal);
    TimerIsRunning = 1;
}
