summaryrefslogtreecommitdiffstats
path: root/src/H5timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5timer.c')
-rw-r--r--src/H5timer.c704
1 files changed, 539 insertions, 165 deletions
diff --git a/src/H5timer.c b/src/H5timer.c
index 7bdee8a..7065814 100644
--- a/src/H5timer.c
+++ b/src/H5timer.c
@@ -1,25 +1,21 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
- * Copyright by the Board of Trustees of the University of Illinois. *
* 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. *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://www.hdfgroup.org/licenses. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*-------------------------------------------------------------------------
- *
* Created: H5timer.c
* Aug 21 2006
- * Quincey Koziol <koziol@hdfgroup.org>
+ * Quincey Koziol
*
- * Purpose: Internal 'timer' routines & support routines.
+ * Purpose: Internal, platform-independent 'timer' support routines.
*
*-------------------------------------------------------------------------
*/
@@ -27,256 +23,634 @@
/****************/
/* Module Setup */
/****************/
-
+#include "H5module.h" /* This source code file is part of the H5 module */
/***********/
/* Headers */
/***********/
-#include "H5private.h" /* Generic Functions */
-
-/* We need this for the struct rusage declaration */
-#if defined(H5_HAVE_GETRUSAGE) && defined(H5_HAVE_SYS_RESOURCE_H)
-# include <sys/resource.h>
-#endif
-
-#if defined(H5_HAVE_GETTIMEOFDAY) && defined(H5_HAVE_SYS_TIME_H)
-#include <sys/time.h>
-#endif
-
+#include "H5private.h" /* Generic Functions */
/****************/
/* Local Macros */
/****************/
+/* Size of a generated time string.
+ * Most time strings should be < 20 or so characters (max!) so this should be a
+ * safe size. Dynamically allocating the correct size would be painful.
+ */
+#define H5TIMER_TIME_STRING_LEN 1536
+
+/* Conversion factors */
+#define H5_SEC_PER_DAY (24.0 * 60.0 * 60.0)
+#define H5_SEC_PER_HOUR (60.0 * 60.0)
+#define H5_SEC_PER_MIN (60.0)
/******************/
/* Local Typedefs */
/******************/
-
/********************/
/* Package Typedefs */
/********************/
-
/********************/
/* Local Prototypes */
/********************/
-
/*********************/
/* Package Variables */
/*********************/
-
/*****************************/
/* Library Private Variables */
/*****************************/
-
/*******************/
/* Local Variables */
/*******************/
-
/*-------------------------------------------------------------------------
- * Function: H5_timer_reset
+ * Function: H5_bandwidth
*
- * Purpose: Resets the timer struct to zero. Use this to reset a timer
- * that's being used as an accumulator for summing times.
+ * Purpose: Prints the bandwidth (bytes per second) in a field 10
+ * characters wide widh four digits of precision like this:
+ *
+ * NaN If <=0 seconds
+ * 1234. TB/s
+ * 123.4 TB/s
+ * 12.34 GB/s
+ * 1.234 MB/s
+ * 4.000 kB/s
+ * 1.000 B/s
+ * 0.000 B/s If NBYTES==0
+ * 1.2345e-10 For bandwidth less than 1
+ * 6.7893e+94 For exceptionally large values
+ * 6.678e+106 For really big values
*
* Return: void
*
* Programmer: Robb Matzke
- * Thursday, April 16, 1998
- *
- * Modifications:
+ * Wednesday, August 5, 1998
*
*-------------------------------------------------------------------------
*/
void
-H5_timer_reset (H5_timer_t *timer)
+H5_bandwidth(char *buf /*out*/, size_t bufsize, double nbytes, double nseconds)
{
- assert (timer);
- HDmemset (timer, 0, sizeof *timer);
-} /* end H5_timer_reset() */
+ double bw;
+
+ if (nseconds <= 0.0)
+ HDstrcpy(buf, " NaN");
+ else {
+ bw = nbytes / nseconds;
+ if (H5_DBL_ABS_EQUAL(bw, 0.0))
+ HDstrcpy(buf, "0.000 B/s");
+ else if (bw < 1.0)
+ HDsnprintf(buf, bufsize, "%10.4e", bw);
+ else if (bw < (double)H5_KB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw);
+ HDstrcpy(buf + 5, " B/s");
+ }
+ else if (bw < (double)H5_MB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw / (double)H5_KB);
+ HDstrcpy(buf + 5, " kB/s");
+ }
+ else if (bw < (double)H5_GB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw / (double)H5_MB);
+ HDstrcpy(buf + 5, " MB/s");
+ }
+ else if (bw < (double)H5_TB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw / (double)H5_GB);
+ HDstrcpy(buf + 5, " GB/s");
+ }
+ else if (bw < (double)H5_PB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw / (double)H5_TB);
+ HDstrcpy(buf + 5, " TB/s");
+ }
+ else if (bw < (double)H5_EB) {
+ HDsnprintf(buf, bufsize, "%05.4f", bw / (double)H5_PB);
+ HDstrcpy(buf + 5, " PB/s");
+ }
+ else {
+ HDsnprintf(buf, bufsize, "%10.4e", bw);
+ if (HDstrlen(buf) > 10)
+ HDsnprintf(buf, bufsize, "%10.3e", bw);
+ } /* end else-if */
+ } /* end else */
+} /* end H5_bandwidth() */
-
/*-------------------------------------------------------------------------
- * Function: H5_timer_begin
- *
- * Purpose: Initialize a timer to time something.
+ * Function: H5_now
*
- * Return: void
+ * Purpose: Retrieves the current time, as seconds after the UNIX epoch.
*
- * Programmer: Robb Matzke
- * Thursday, April 16, 1998
+ * Return: # of seconds from the epoch (can't fail)
*
- * Modifications:
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
*
*-------------------------------------------------------------------------
*/
-void
-H5_timer_begin (H5_timer_t *timer)
+time_t
+H5_now(void)
{
-#ifdef H5_HAVE_GETRUSAGE
- struct rusage rusage;
-#endif
+ time_t now; /* Current time */
+
#ifdef H5_HAVE_GETTIMEOFDAY
- struct timeval etime;
-#endif
+ {
+ struct timeval now_tv;
+
+ HDgettimeofday(&now_tv, NULL);
+ now = now_tv.tv_sec;
+ }
+#else /* H5_HAVE_GETTIMEOFDAY */
+ now = HDtime(NULL);
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ return (now);
+} /* end H5_now() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_now_usec
+ *
+ * Purpose: Retrieves the current time, as microseconds after the UNIX epoch.
+ *
+ * Return: # of microseconds from the epoch (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, November 28, 2006
+ *
+ *-------------------------------------------------------------------------
+ */
+uint64_t
+H5_now_usec(void)
+{
+ uint64_t now; /* Current time, in microseconds */
+
+#if defined(H5_HAVE_CLOCK_GETTIME)
+ {
+ struct timespec ts;
- assert (timer);
+ HDclock_gettime(CLOCK_MONOTONIC, &ts);
+
+ /* Cast all values in this expression to uint64_t to ensure that all intermediate
+ * calculations are done in 64 bit, to prevent overflow */
+ now = ((uint64_t)ts.tv_sec * ((uint64_t)1000 * (uint64_t)1000)) +
+ ((uint64_t)ts.tv_nsec / (uint64_t)1000);
+ }
+#elif defined(H5_HAVE_GETTIMEOFDAY)
+ {
+ struct timeval now_tv;
+
+ HDgettimeofday(&now_tv, NULL);
-#ifdef H5_HAVE_GETRUSAGE
- HDgetrusage (RUSAGE_SELF, &rusage);
- timer->utime = (double)rusage.ru_utime.tv_sec +
- ((double)rusage.ru_utime.tv_usec / 1e6);
- timer->stime = (double)rusage.ru_stime.tv_sec +
- ((double)rusage.ru_stime.tv_usec / 1e6);
+ /* Cast all values in this expression to uint64_t to ensure that all intermediate
+ * calculations are done in 64 bit, to prevent overflow */
+ now = ((uint64_t)now_tv.tv_sec * ((uint64_t)1000 * (uint64_t)1000)) + (uint64_t)now_tv.tv_usec;
+ }
+#else /* H5_HAVE_GETTIMEOFDAY */
+ /* Cast all values in this expression to uint64_t to ensure that all intermediate calculations
+ * are done in 64 bit, to prevent overflow */
+ now = ((uint64_t)HDtime(NULL) * ((uint64_t)1000 * (uint64_t)1000));
+#endif /* H5_HAVE_GETTIMEOFDAY */
+
+ return (now);
+} /* end H5_now_usec() */
+
+/*--------------------------------------------------------------------------
+ * Function: H5_get_time
+ *
+ * Purpose: Get the current time, as the time of seconds after the UNIX epoch
+ *
+ * Return: Success: A non-negative time value
+ * Failure: -1.0 (in theory, can't currently fail)
+ *
+ * Programmer: Quincey Koziol
+ * October 05, 2016
+ *--------------------------------------------------------------------------
+ */
+double
+H5_get_time(void)
+{
+ double ret_value = 0.0;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+#if defined(H5_HAVE_CLOCK_GETTIME)
+ {
+ struct timespec ts;
+
+ HDclock_gettime(CLOCK_MONOTONIC, &ts);
+ ret_value = (double)ts.tv_sec + ((double)ts.tv_nsec / 1000000000.0);
+ }
+#elif defined(H5_HAVE_GETTIMEOFDAY)
+ {
+ struct timeval now_tv;
+
+ HDgettimeofday(&now_tv, NULL);
+ ret_value = (double)now_tv.tv_sec + ((double)now_tv.tv_usec / 1000000.0);
+ }
#else
- timer->utime = 0.0;
- timer->stime = 0.0;
+ ret_value = (double)HDtime(NULL);
#endif
-#ifdef H5_HAVE_GETTIMEOFDAY
- HDgettimeofday (&etime, NULL);
- timer->etime = (double)etime.tv_sec + ((double)etime.tv_usec / 1e6);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5_get_time() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5__timer_get_timevals
+ *
+ * Purpose: Internal platform-specific function to get time system,
+ * user and elapsed time values.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5__timer_get_timevals(H5_timevals_t *times /*in,out*/)
+{
+ /* Sanity check */
+ HDassert(times);
+
+ /* Windows call handles both system/user and elapsed times */
+#ifdef H5_HAVE_WIN32_API
+ if (H5_get_win32_times(times) < 0) {
+ times->elapsed = -1.0;
+ times->system = -1.0;
+ times->user = -1.0;
+
+ return -1;
+ } /* end if */
+#else /* H5_HAVE_WIN32_API */
+
+ /*************************
+ * System and user times *
+ *************************/
+#if defined(H5_HAVE_GETRUSAGE)
+ {
+ struct rusage res;
+
+ if (HDgetrusage(RUSAGE_SELF, &res) < 0)
+ return -1;
+ times->system = (double)res.ru_stime.tv_sec + ((double)res.ru_stime.tv_usec / 1.0E6);
+ times->user = (double)res.ru_utime.tv_sec + ((double)res.ru_utime.tv_usec / 1.0E6);
+ }
#else
- timer->etime = 0.0;
+ /* No suitable way to get system/user times */
+ /* This is not an error condition, they just won't be available */
+ times->system = -1.0;
+ times->user = -1.0;
#endif
-} /* end H5_timer_begin() */
-
+ /****************
+ * Elapsed time *
+ ****************/
+
+ times->elapsed = H5_get_time();
+
+#endif /* H5_HAVE_WIN32_API */
+
+ return 0;
+} /* end H5__timer_get_timevals() */
+
/*-------------------------------------------------------------------------
- * Function: H5_timer_end
+ * Function: H5_timer_init
*
- * Purpose: This function should be called at the end of a timed region.
- * The SUM is an optional pointer which will accumulate times.
- * TMS is the same struct that was passed to H5_timer_start().
- * On return, TMS will contain total times for the timed region.
+ * Purpose: Initialize a platform-independent timer.
*
- * Return: void
+ * Timer usage is as follows:
*
- * Programmer: Robb Matzke
- * Thursday, April 16, 1998
+ * 1) Call H5_timer_init(), passing in a timer struct, to set
+ * up the timer.
+ *
+ * 2) Wrap any code you'd like to time with calls to
+ * H5_timer_start/stop(). For accurate timing, place these
+ * calls as close to the code of interest as possible. You
+ * can call start/stop multiple times on the same timer -
+ * when you do this, H5_timer_get_times() will return time
+ * values for the current/last session and
+ * H5_timer_get_total_times() will return the summed times
+ * of all sessions (see #3 and #4, below).
+ *
+ * 3) Use H5_timer_get_times() to get the current system, user
+ * and elapsed times from a running timer. If called on a
+ * stopped timer, this will return the time recorded at the
+ * stop point.
+ *
+ * 4) Call H5_timer_get_total_times() to get the total system,
+ * user and elapsed times recorded across multiple start/stop
+ * sessions. If called on a running timer, it will return the
+ * time recorded up to that point. On a stopped timer, it
+ * will return the time recorded at the stop point.
+ *
+ * NOTE: Obtaining a time point is not free! Keep in mind that
+ * the time functions make system calls and can have
+ * non-trivial overhead. If you call one of the get_time
+ * functions on a running timer, that overhead will be
+ * added to the reported times.
+ *
+ * 5) All times recorded will be in seconds. These can be
+ * converted into human-readable strings with the
+ * H5_timer_get_time_string() function.
+ *
+ * 6) A timer can be reset using by calling H5_timer_init() on
+ * it. This will set its state to 'stopped' and reset all
+ * accumulated times to zero.
*
- * Modifications:
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
*
*-------------------------------------------------------------------------
*/
-void
-H5_timer_end (H5_timer_t *sum/*in,out*/, H5_timer_t *timer/*in,out*/)
+herr_t
+H5_timer_init(H5_timer_t *timer /*in,out*/)
{
- H5_timer_t now;
+ /* Sanity check */
+ HDassert(timer);
- assert (timer);
- H5_timer_begin (&now);
+ /* Initialize everything */
+ HDmemset(timer, 0, sizeof(H5_timer_t));
- timer->utime = MAX(0.0, now.utime - timer->utime);
- timer->stime = MAX(0.0, now.stime - timer->stime);
- timer->etime = MAX(0.0, now.etime - timer->etime);
+ return 0;
+} /* end H5_timer_init() */
- if (sum) {
- sum->utime += timer->utime;
- sum->stime += timer->stime;
- sum->etime += timer->etime;
- }
-} /* end H5_timer_end() */
-
-
/*-------------------------------------------------------------------------
- * Function: H5_bandwidth
+ * Function: H5_timer_start
*
- * Purpose: Prints the bandwidth (bytes per second) in a field 10
- * characters wide widh four digits of precision like this:
+ * Purpose: Start tracking time in a platform-independent timer.
*
- * NaN If <=0 seconds
- * 1234. TB/s
- * 123.4 TB/s
- * 12.34 GB/s
- * 1.234 MB/s
- * 4.000 kB/s
- * 1.000 B/s
- * 0.000 B/s If NBYTES==0
- * 1.2345e-10 For bandwidth less than 1
- * 6.7893e+94 For exceptionally large values
- * 6.678e+106 For really big values
+ * Return: Success: 0
+ * Failure: -1
*
- * Return: void
+ * Programmer: Dana Robinson
+ * May 2011
*
- * Programmer: Robb Matzke
- * Wednesday, August 5, 1998
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_timer_start(H5_timer_t *timer /*in,out*/)
+{
+ /* Sanity check */
+ HDassert(timer);
+
+ /* Start the timer
+ * This sets the "initial" times to the system-defined start times.
+ */
+ if (H5__timer_get_timevals(&(timer->initial)) < 0)
+ return -1;
+
+ timer->is_running = TRUE;
+
+ return 0;
+} /* end H5_timer_start() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_stop
+ *
+ * Purpose: Stop tracking time in a platform-independent timer.
*
- * Modifications:
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
*
*-------------------------------------------------------------------------
*/
-void
-H5_bandwidth(char *buf/*out*/, double nbytes, double nseconds)
+herr_t
+H5_timer_stop(H5_timer_t *timer /*in,out*/)
{
- double bw;
+ /* Sanity check */
+ HDassert(timer);
- if(nseconds <= 0.0)
- HDstrcpy(buf, " NaN");
- else {
- bw = nbytes/nseconds;
- if(fabs(bw) < 0.0000000001)
- /* That is == 0.0, but direct comparison between floats is bad */
- HDstrcpy(buf, "0.000 B/s");
- else if(bw < 1.0)
- sprintf(buf, "%10.4e", bw);
- else if(bw < 1024.0) {
- sprintf(buf, "%05.4f", bw);
- HDstrcpy(buf+5, " B/s");
- } else if(bw < (1024.0 * 1024.0)) {
- sprintf(buf, "%05.4f", bw / 1024.0);
- HDstrcpy(buf+5, " kB/s");
- } else if(bw < (1024.0 * 1024.0 * 1024.0)) {
- sprintf(buf, "%05.4f", bw / (1024.0 * 1024.0));
- HDstrcpy(buf+5, " MB/s");
- } else if(bw < (1024.0 * 1024.0 * 1024.0 * 1024.0)) {
- sprintf(buf, "%05.4f", bw / (1024.0 * 1024.0 * 1024.0));
- HDstrcpy(buf+5, " GB/s");
- } else if(bw < (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0)) {
- sprintf(buf, "%05.4f", bw / (1024.0 * 1024.0 * 1024.0 * 1024.0));
- HDstrcpy(buf+5, " TB/s");
- } else {
- sprintf(buf, "%10.4e", bw);
- if(HDstrlen(buf) > 10)
- sprintf(buf, "%10.3e", bw);
- }
- }
-} /* end H5_bandwidth() */
+ /* Stop the timer */
+ if (H5__timer_get_timevals(&(timer->final_interval)) < 0)
+ return -1;
+
+ /* The "final" times are stored as intervals (final - initial)
+ * for more useful reporting to the user.
+ */
+ timer->final_interval.elapsed = timer->final_interval.elapsed - timer->initial.elapsed;
+ timer->final_interval.system = timer->final_interval.system - timer->initial.system;
+ timer->final_interval.user = timer->final_interval.user - timer->initial.user;
+
+ /* Add the intervals to the elapsed time */
+ timer->total.elapsed += timer->final_interval.elapsed;
+ timer->total.system += timer->final_interval.system;
+ timer->total.user += timer->final_interval.user;
+
+ timer->is_running = FALSE;
+
+ return 0;
+} /* end H5_timer_stop() */
-
/*-------------------------------------------------------------------------
- * Function: H5_now
+ * Function: H5_timer_get_times
*
- * Purpose: Retrieves the current time, as seconds after the UNIX epoch.
+ * Purpose: Get the system, user and elapsed times from a timer. These
+ * are the times since the timer was last started and will be
+ * 0.0 in a timer that has not been started since it was
+ * initialized.
*
- * Return: # of seconds from the epoch (can't fail)
+ * This function can be called either before or after
+ * H5_timer_stop() has been called. If it is called before the
+ * stop function, the timer will continue to run.
*
- * Programmer: Quincey Koziol
- * Tuesday, November 28, 2006
+ * The system and user times will be -1.0 if those times cannot
+ * be computed on a particular platform. The elapsed time will
+ * always be present.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
*
*-------------------------------------------------------------------------
*/
-time_t
-H5_now(void)
+herr_t
+H5_timer_get_times(H5_timer_t timer, H5_timevals_t *times /*in,out*/)
{
- time_t now; /* Current time */
+ /* Sanity check */
+ HDassert(times);
+
+ if (timer.is_running) {
+ H5_timevals_t now;
+
+ /* Get the current times and report the current intervals without
+ * stopping the timer.
+ */
+ if (H5__timer_get_timevals(&now) < 0)
+ return -1;
+
+ times->elapsed = now.elapsed - timer.initial.elapsed;
+ times->system = now.system - timer.initial.system;
+ times->user = now.user - timer.initial.user;
+ } /* end if */
+ else {
+ times->elapsed = timer.final_interval.elapsed;
+ times->system = timer.final_interval.system;
+ times->user = timer.final_interval.user;
+ } /* end else */
-#ifdef H5_HAVE_GETTIMEOFDAY
- {
- struct timeval now_tv;
+ return 0;
+} /* end H5_timer_get_times() */
- HDgettimeofday(&now_tv, NULL);
- now = now_tv.tv_sec;
- }
-#else /* H5_HAVE_GETTIMEOFDAY */
- now = HDtime(NULL);
-#endif /* H5_HAVE_GETTIMEOFDAY */
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_get_total_times
+ *
+ * Purpose: Get the TOTAL system, user and elapsed times recorded by
+ * the timer since its initialization. This is the sum of all
+ * times recorded while the timer was running.
+ *
+ * These will be 0.0 in a timer that has not been started
+ * since it was initialized. Calling H5_timer_init() on a
+ * timer will reset these values to 0.0.
+ *
+ * This function can be called either before or after
+ * H5_timer_stop() has been called. If it is called before the
+ * stop function, the timer will continue to run.
+ *
+ * The system and user times will be -1.0 if those times cannot
+ * be computed on a particular platform. The elapsed time will
+ * always be present.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ * Programmer: Dana Robinson
+ * May 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5_timer_get_total_times(H5_timer_t timer, H5_timevals_t *times /*in,out*/)
+{
+ /* Sanity check */
+ HDassert(times);
+
+ if (timer.is_running) {
+ H5_timevals_t now;
+
+ /* Get the current times and report the current totals without
+ * stopping the timer.
+ */
+ if (H5__timer_get_timevals(&now) < 0)
+ return -1;
+
+ times->elapsed = timer.total.elapsed + (now.elapsed - timer.initial.elapsed);
+ times->system = timer.total.system + (now.system - timer.initial.system);
+ times->user = timer.total.user + (now.user - timer.initial.user);
+ } /* end if */
+ else {
+ times->elapsed = timer.total.elapsed;
+ times->system = timer.total.system;
+ times->user = timer.total.user;
+ } /* end else */
- return(now);
-} /* end H5_now() */
+ return 0;
+} /* end H5_timer_get_total_times() */
+/*-------------------------------------------------------------------------
+ * Function: H5_timer_get_time_string
+ *
+ * Purpose: Converts a time (in seconds) into a human-readable string
+ * suitable for log messages.
+ *
+ * Return: Success: The time string.
+ *
+ * The general format of the time string is:
+ *
+ * "N/A" time < 0 (invalid time)
+ * "%.f ns" time < 1 microsecond
+ * "%.1f us" time < 1 millisecond
+ * "%.1f ms" time < 1 second
+ * "%.2f s" time < 1 minute
+ * "%.f m %.f s" time < 1 hour
+ * "%.f h %.f m %.f s" longer times
+ *
+ * Failure: NULL
+ *
+ * Programmer: Dana Robinson
+ * May 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+char *
+H5_timer_get_time_string(double seconds)
+{
+ char *s; /* output string */
+
+ /* Used when the time is greater than 59 seconds */
+ double days = 0.0;
+ double hours = 0.0;
+ double minutes = 0.0;
+ double remainder_sec = 0.0;
+
+ /* Extract larger time units from count of seconds */
+ if (seconds > 60.0) {
+ /* Set initial # of seconds */
+ remainder_sec = seconds;
+
+ /* Extract days */
+ days = HDfloor(remainder_sec / H5_SEC_PER_DAY);
+ remainder_sec -= (days * H5_SEC_PER_DAY);
+
+ /* Extract hours */
+ hours = HDfloor(remainder_sec / H5_SEC_PER_HOUR);
+ remainder_sec -= (hours * H5_SEC_PER_HOUR);
+
+ /* Extract minutes */
+ minutes = HDfloor(remainder_sec / H5_SEC_PER_MIN);
+ remainder_sec -= (minutes * H5_SEC_PER_MIN);
+
+ /* The # of seconds left is in remainder_sec */
+ } /* end if */
+
+ /* Allocate */
+ if (NULL == (s = (char *)HDcalloc(H5TIMER_TIME_STRING_LEN, sizeof(char))))
+ return NULL;
+
+ /* Do we need a format string? Some people might like a certain
+ * number of milliseconds or s before spilling to the next highest
+ * time unit. Perhaps this could be passed as an integer.
+ * (name? round_up_size? ?)
+ */
+ if (seconds < 0.0)
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "N/A");
+ else if (H5_DBL_ABS_EQUAL(0.0, seconds))
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "0.0 s");
+ else if (seconds < 1.0E-6)
+ /* t < 1 us, Print time in ns */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.f ns", seconds * 1.0E9);
+ else if (seconds < 1.0E-3)
+ /* t < 1 ms, Print time in us */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.1f us", seconds * 1.0E6);
+ else if (seconds < 1.0)
+ /* t < 1 s, Print time in ms */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.1f ms", seconds * 1.0E3);
+ else if (seconds < H5_SEC_PER_MIN)
+ /* t < 1 m, Print time in s */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.2f s", seconds);
+ else if (seconds < H5_SEC_PER_HOUR)
+ /* t < 1 h, Print time in m and s */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.f m %.f s", minutes, remainder_sec);
+ else if (seconds < H5_SEC_PER_DAY)
+ /* t < 1 d, Print time in h, m and s */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.f h %.f m %.f s", hours, minutes, remainder_sec);
+ else
+ /* Print time in d, h, m and s */
+ HDsnprintf(s, H5TIMER_TIME_STRING_LEN, "%.f d %.f h %.f m %.f s", days, hours, minutes,
+ remainder_sec);
+
+ return s;
+} /* end H5_timer_get_time_string() */