/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
 * of the source code distribution tree; Copyright.html can be found at the  *
 * root level of an installed copy of the electronic HDF5 document set and   *
 * is linked from the top-level documents page.  It can also be found at     *
 * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
 * access to either file, you may request a copy from help@hdfgroup.org.     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 * Purpose:
 *
 * This is a module of useful timing functions for performance testing.
 */

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

#include "sio_timer.h"


#include "sio_perf.h"

/*
 * The number to divide the tv_usec field with to get a nice decimal to add to
 * the number of seconds.
 */
#define MICROSECOND     1000000.0

/* global variables */
sio_time   *timer_g;            /* timer: global for stub functions     */

/*
 * Function:  sub_time
 * Purpose:   Struct two time values, and return the difference, in microseconds
 *
 * 	      Note that the function assumes that a > b
 * Programmer: Leon Arber, 1/27/06
 */
static double sub_time(struct timeval* a, struct timeval* b)
{
    return (((double)a->tv_sec +
     ((double)a->tv_usec) / MICROSECOND) -
	((double)b->tv_sec +
	 ((double)b->tv_usec) / MICROSECOND));
}


/*
 * Function:    sio_time_new
 * Purpose:     Build us a brand, spankin', new performance time object.
 *              The object is a black box to the user.
 * Return:      Pointer to sio_time object
 * Programmer:  Bill Wendling, 01. October 2001
 * Modifications:
 */
sio_time *
sio_time_new(void)
{
    sio_time *pt = (sio_time *)calloc(1, sizeof(struct sio_time_));

    /* set global timer variable */
    timer_g = pt;

    return pt;
}

/*
 * Function:    sio_time_destroy
 * Purpose:     Remove the memory allocated for the sio_time object. Only
 *              need to call on a pointer allocated with the ``sio_time_new''
 *              function.
 * Return:      Nothing
 * Programmer:  Bill Wendling, 01. October 2001
 * Modifications:
 */
void
sio_time_destroy(sio_time *pt)
{
    free(pt);
    /* reset the global timer pointer too. */
    timer_g = NULL;
}



/*
 * Function:    set_time
 * Purpose:     Set the time in a ``sio_time'' object.
 * Return:      Pointer to the passed in ``sio_time'' object.
 * Programmer:  Bill Wendling, 01. October 2001
 * Modifications:
 */
sio_time *
set_time(sio_time *pt, timer_type t, int start_stop)
{
    if (pt) {
            if (start_stop == START) {
                HDgettimeofday(&pt->sys_timer[t], NULL);

		/* When we start the timer for HDF5_FINE_WRITE_FIXED_DIMS or HDF5_FINE_READ_FIXED_DIMS
		 * we compute the time it took to only open the file */
		if(t == HDF5_FINE_WRITE_FIXED_DIMS)
		    pt->total_time[HDF5_FILE_WRITE_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_WRITE_FIXED_DIMS]));
		else if(t == HDF5_FINE_READ_FIXED_DIMS)
		    pt->total_time[HDF5_FILE_READ_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_READ_FIXED_DIMS]));


            } else {
                struct timeval sys_t;

                HDgettimeofday(&sys_t, NULL);
                pt->total_time[t] += sub_time(&sys_t, &(pt->sys_timer[t]));

/*                    ((double)sys_t.tv_sec +
                                ((double)sys_t.tv_usec) / MICROSECOND) -
                    ((double)pt->sys_timer[t].tv_sec +
                            ((double)pt->sys_timer[t].tv_usec) / MICROSECOND);*/

		/* When we stop the timer for HDF5_GROSS_WRITE_FIXED_DIMS or HDF5_GROSS_READ_FIXED_DIMS
		 * we compute the time it took to close the file after the last read/write finished */
		if(t == HDF5_GROSS_WRITE_FIXED_DIMS)
		    pt->total_time[HDF5_FILE_WRITE_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_WRITE_FIXED_DIMS]));
		else if(t == HDF5_GROSS_READ_FIXED_DIMS)
		    pt->total_time[HDF5_FILE_READ_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_READ_FIXED_DIMS]));

            }

        if (sio_debug_level >= 4) {
            const char *msg;

            switch (t) {
            case HDF5_FILE_OPENCLOSE:
                msg = "File Open/Close";
                break;
            case HDF5_DATASET_CREATE:
                msg = "Dataset Create";
                break;
            case HDF5_MPI_WRITE:
                msg = "MPI Write";
                break;
            case HDF5_MPI_READ:
                msg = "MPI Read";
                break;
            case HDF5_FINE_WRITE_FIXED_DIMS:
                msg = "Fine Write";
                break;
            case HDF5_FINE_READ_FIXED_DIMS:
                msg = "Fine Read";
                break;
            case HDF5_GROSS_WRITE_FIXED_DIMS:
                msg = "Gross Write";
                break;
            case HDF5_GROSS_READ_FIXED_DIMS:
                msg = "Gross Read";
                break;
            case HDF5_RAW_WRITE_FIXED_DIMS:
                msg = "Raw Write";
                break;
            case HDF5_RAW_READ_FIXED_DIMS:
                msg = "Raw Read";
                break;
            default:
                msg = "Unknown Timer";
                break;
            }

            fprintf(output, "    %s %s: %.2f\n", msg,
                    (start_stop == START ? "Start" : "Stop"),
                    pt->total_time[t]);
        }
    }

    return pt;
}

/*
 * Function:    get_time
 * Purpose:     Get the time from a ``sio_time'' object.
 * Return:      The number of seconds as a DOUBLE.
 * Programmer:  Bill Wendling, 01. October 2001
 * Modifications:
 */
double
get_time(sio_time *pt, timer_type t)
{
    return pt->total_time[t];
}
#ifdef STANDALONE
#include "sio_standalone.c"
#endif

