Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * H5timer.c |
15 | | * |
16 | | * Internal, platform-independent 'timer' support routines |
17 | | *------------------------------------------------------------------------- |
18 | | */ |
19 | | |
20 | | #include "H5module.h" /* This source code file is part of the H5 module */ |
21 | | |
22 | | #include "H5private.h" |
23 | | |
24 | | /* Size of a generated time string. |
25 | | * Most time strings should be < 20 or so characters (max!) so this should be a |
26 | | * safe size. Dynamically allocating the correct size would be painful. |
27 | | */ |
28 | 0 | #define H5TIMER_TIME_STRING_LEN 1536 |
29 | | |
30 | | /* Conversion factors */ |
31 | 0 | #define H5_SEC_PER_DAY (24.0 * 60.0 * 60.0) |
32 | 0 | #define H5_SEC_PER_HOUR (60.0 * 60.0) |
33 | 0 | #define H5_SEC_PER_MIN (60.0) |
34 | | |
35 | | /*------------------------------------------------------------------------- |
36 | | * Function: H5_bandwidth |
37 | | * |
38 | | * Purpose: Prints the bandwidth (bytes per second) in a field 10 |
39 | | * characters wide widh four digits of precision like this: |
40 | | * |
41 | | * NaN If <=0 seconds |
42 | | * 1234. TB/s |
43 | | * 123.4 TB/s |
44 | | * 12.34 GB/s |
45 | | * 1.234 MB/s |
46 | | * 4.000 kB/s |
47 | | * 1.000 B/s |
48 | | * 0.000 B/s If NBYTES==0 |
49 | | * 1.2345e-10 For bandwidth less than 1 |
50 | | * 6.7893e+94 For exceptionally large values |
51 | | * 6.678e+106 For really big values |
52 | | * |
53 | | * Return: void |
54 | | *------------------------------------------------------------------------- |
55 | | */ |
56 | | void |
57 | | H5_bandwidth(char *buf /*out*/, size_t bufsize, double nbytes, double nseconds) |
58 | 0 | { |
59 | 0 | double bw; |
60 | |
|
61 | 0 | if (nseconds <= 0.0) |
62 | 0 | strcpy(buf, " NaN"); |
63 | 0 | else { |
64 | 0 | bw = nbytes / nseconds; |
65 | 0 | if (H5_DBL_ABS_EQUAL(bw, 0.0)) |
66 | 0 | strcpy(buf, "0.000 B/s"); |
67 | 0 | else if (bw < 1.0) |
68 | 0 | snprintf(buf, bufsize, "%10.4e", bw); |
69 | 0 | else if (bw < (double)H5_KB) { |
70 | 0 | snprintf(buf, bufsize, "%05.4f", bw); |
71 | 0 | strcpy(buf + 5, " B/s"); |
72 | 0 | } |
73 | 0 | else if (bw < (double)H5_MB) { |
74 | 0 | snprintf(buf, bufsize, "%05.4f", bw / (double)H5_KB); |
75 | 0 | strcpy(buf + 5, " kB/s"); |
76 | 0 | } |
77 | 0 | else if (bw < (double)H5_GB) { |
78 | 0 | snprintf(buf, bufsize, "%05.4f", bw / (double)H5_MB); |
79 | 0 | strcpy(buf + 5, " MB/s"); |
80 | 0 | } |
81 | 0 | else if (bw < (double)H5_TB) { |
82 | 0 | snprintf(buf, bufsize, "%05.4f", bw / (double)H5_GB); |
83 | 0 | strcpy(buf + 5, " GB/s"); |
84 | 0 | } |
85 | 0 | else if (bw < (double)H5_PB) { |
86 | 0 | snprintf(buf, bufsize, "%05.4f", bw / (double)H5_TB); |
87 | 0 | strcpy(buf + 5, " TB/s"); |
88 | 0 | } |
89 | 0 | else if (bw < (double)H5_EB) { |
90 | 0 | snprintf(buf, bufsize, "%05.4f", bw / (double)H5_PB); |
91 | 0 | strcpy(buf + 5, " PB/s"); |
92 | 0 | } |
93 | 0 | else { |
94 | 0 | snprintf(buf, bufsize, "%10.4e", bw); |
95 | 0 | if (strlen(buf) > 10) |
96 | 0 | snprintf(buf, bufsize, "%10.3e", bw); |
97 | 0 | } |
98 | 0 | } |
99 | 0 | } /* end H5_bandwidth() */ |
100 | | |
101 | | /*------------------------------------------------------------------------- |
102 | | * Function: H5_now |
103 | | * |
104 | | * Purpose: Retrieves the current time, as seconds after the UNIX epoch. |
105 | | * |
106 | | * Return: # of seconds from the epoch (can't fail) |
107 | | *------------------------------------------------------------------------- |
108 | | */ |
109 | | time_t |
110 | | H5_now(void) |
111 | 0 | { |
112 | 0 | time_t now; /* Current time */ |
113 | |
|
114 | 0 | #ifdef H5_HAVE_GETTIMEOFDAY |
115 | 0 | { |
116 | 0 | struct timeval now_tv; |
117 | |
|
118 | 0 | HDgettimeofday(&now_tv, NULL); |
119 | 0 | now = now_tv.tv_sec; |
120 | 0 | } |
121 | | #else |
122 | | now = time(NULL); |
123 | | #endif |
124 | |
|
125 | 0 | return now; |
126 | 0 | } /* end H5_now() */ |
127 | | |
128 | | /*------------------------------------------------------------------------- |
129 | | * Function: H5_now_usec |
130 | | * |
131 | | * Purpose: Retrieves the current time, as microseconds after the UNIX epoch. |
132 | | * |
133 | | * Return: # of microseconds from the epoch (can't fail) |
134 | | *------------------------------------------------------------------------- |
135 | | */ |
136 | | uint64_t |
137 | | H5_now_usec(void) |
138 | 0 | { |
139 | 0 | uint64_t now; /* Current time, in microseconds */ |
140 | |
|
141 | 0 | #if defined(H5_HAVE_CLOCK_GETTIME) |
142 | 0 | { |
143 | 0 | struct timespec ts; |
144 | |
|
145 | 0 | clock_gettime(CLOCK_MONOTONIC, &ts); |
146 | | |
147 | | /* Cast all values in this expression to uint64_t to ensure that all intermediate |
148 | | * calculations are done in 64 bit, to prevent overflow */ |
149 | 0 | now = ((uint64_t)ts.tv_sec * ((uint64_t)1000 * (uint64_t)1000)) + |
150 | 0 | ((uint64_t)ts.tv_nsec / (uint64_t)1000); |
151 | 0 | } |
152 | | #elif defined(H5_HAVE_GETTIMEOFDAY) |
153 | | { |
154 | | struct timeval now_tv; |
155 | | |
156 | | HDgettimeofday(&now_tv, NULL); |
157 | | |
158 | | /* Cast all values in this expression to uint64_t to ensure that all intermediate |
159 | | * calculations are done in 64 bit, to prevent overflow */ |
160 | | now = ((uint64_t)now_tv.tv_sec * ((uint64_t)1000 * (uint64_t)1000)) + (uint64_t)now_tv.tv_usec; |
161 | | } |
162 | | #else |
163 | | /* Cast all values in this expression to uint64_t to ensure that all intermediate calculations |
164 | | * are done in 64 bit, to prevent overflow */ |
165 | | now = ((uint64_t)time(NULL) * ((uint64_t)1000 * (uint64_t)1000)); |
166 | | #endif |
167 | |
|
168 | 0 | return now; |
169 | 0 | } /* end H5_now_usec() */ |
170 | | |
171 | | /*-------------------------------------------------------------------------- |
172 | | * Function: H5_get_time |
173 | | * |
174 | | * Purpose: Get the current time, as the time of seconds after the UNIX epoch |
175 | | * |
176 | | * Return: Success: A non-negative time value |
177 | | * Failure: -1.0 (in theory, can't currently fail) |
178 | | *-------------------------------------------------------------------------- |
179 | | */ |
180 | | double |
181 | | H5_get_time(void) |
182 | 0 | { |
183 | 0 | double ret_value = 0.0; |
184 | |
|
185 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
186 | |
|
187 | 0 | #if defined(H5_HAVE_CLOCK_GETTIME) |
188 | 0 | { |
189 | 0 | struct timespec ts; |
190 | |
|
191 | 0 | clock_gettime(CLOCK_MONOTONIC, &ts); |
192 | 0 | ret_value = (double)ts.tv_sec + ((double)ts.tv_nsec / 1000000000.0); |
193 | 0 | } |
194 | | #elif defined(H5_HAVE_GETTIMEOFDAY) |
195 | | { |
196 | | struct timeval now_tv; |
197 | | |
198 | | HDgettimeofday(&now_tv, NULL); |
199 | | ret_value = (double)now_tv.tv_sec + ((double)now_tv.tv_usec / 1000000.0); |
200 | | } |
201 | | #else |
202 | | ret_value = (double)time(NULL); |
203 | | #endif |
204 | |
|
205 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
206 | 0 | } /* end H5_get_time() */ |
207 | | |
208 | | /*------------------------------------------------------------------------- |
209 | | * Function: H5__timer_get_timevals |
210 | | * |
211 | | * Purpose: Internal platform-specific function to get time system, |
212 | | * user and elapsed time values. |
213 | | * |
214 | | * Return: Success: 0 |
215 | | * Failure: -1 |
216 | | *------------------------------------------------------------------------- |
217 | | */ |
218 | | static herr_t |
219 | | H5__timer_get_timevals(H5_timevals_t *times /*in,out*/) |
220 | 0 | { |
221 | 0 | assert(times); |
222 | | |
223 | | /* Windows call handles both system/user and elapsed times */ |
224 | | #ifdef H5_HAVE_WIN32_API |
225 | | if (H5_get_win32_times(times) < 0) { |
226 | | times->elapsed = -1.0; |
227 | | times->system = -1.0; |
228 | | times->user = -1.0; |
229 | | |
230 | | return -1; |
231 | | } |
232 | | #else /* H5_HAVE_WIN32_API */ |
233 | | |
234 | | /************************* |
235 | | * System and user times * |
236 | | *************************/ |
237 | 0 | #if defined(H5_HAVE_GETRUSAGE) |
238 | 0 | { |
239 | 0 | struct rusage res; |
240 | |
|
241 | 0 | if (getrusage(RUSAGE_SELF, &res) < 0) |
242 | 0 | return -1; |
243 | 0 | times->system = (double)res.ru_stime.tv_sec + ((double)res.ru_stime.tv_usec / 1.0E6); |
244 | 0 | times->user = (double)res.ru_utime.tv_sec + ((double)res.ru_utime.tv_usec / 1.0E6); |
245 | 0 | } |
246 | | #else |
247 | | /* No suitable way to get system/user times */ |
248 | | /* This is not an error condition, they just won't be available */ |
249 | | times->system = -1.0; |
250 | | times->user = -1.0; |
251 | | #endif |
252 | | |
253 | | /**************** |
254 | | * Elapsed time * |
255 | | ****************/ |
256 | | |
257 | 0 | times->elapsed = H5_get_time(); |
258 | |
|
259 | 0 | #endif /* H5_HAVE_WIN32_API */ |
260 | |
|
261 | 0 | return 0; |
262 | 0 | } /* end H5__timer_get_timevals() */ |
263 | | |
264 | | /*------------------------------------------------------------------------- |
265 | | * Function: H5_timer_init |
266 | | * |
267 | | * Purpose: Initialize a platform-independent timer. |
268 | | * |
269 | | * Timer usage is as follows: |
270 | | * |
271 | | * 1) Call H5_timer_init(), passing in a timer struct, to set |
272 | | * up the timer. |
273 | | * |
274 | | * 2) Wrap any code you'd like to time with calls to |
275 | | * H5_timer_start/stop(). For accurate timing, place these |
276 | | * calls as close to the code of interest as possible. You |
277 | | * can call start/stop multiple times on the same timer - |
278 | | * when you do this, H5_timer_get_times() will return time |
279 | | * values for the current/last session and |
280 | | * H5_timer_get_total_times() will return the summed times |
281 | | * of all sessions (see #3 and #4, below). |
282 | | * |
283 | | * 3) Use H5_timer_get_times() to get the current system, user |
284 | | * and elapsed times from a running timer. If called on a |
285 | | * stopped timer, this will return the time recorded at the |
286 | | * stop point. |
287 | | * |
288 | | * 4) Call H5_timer_get_total_times() to get the total system, |
289 | | * user and elapsed times recorded across multiple start/stop |
290 | | * sessions. If called on a running timer, it will return the |
291 | | * time recorded up to that point. On a stopped timer, it |
292 | | * will return the time recorded at the stop point. |
293 | | * |
294 | | * NOTE: Obtaining a time point is not free! Keep in mind that |
295 | | * the time functions make system calls and can have |
296 | | * non-trivial overhead. If you call one of the get_time |
297 | | * functions on a running timer, that overhead will be |
298 | | * added to the reported times. |
299 | | * |
300 | | * 5) All times recorded will be in seconds. These can be |
301 | | * converted into human-readable strings with the |
302 | | * H5_timer_get_time_string() function. |
303 | | * |
304 | | * 6) A timer can be reset using by calling H5_timer_init() on |
305 | | * it. This will set its state to 'stopped' and reset all |
306 | | * accumulated times to zero. |
307 | | * |
308 | | * |
309 | | * Return: Success: 0 |
310 | | * Failure: -1 |
311 | | *------------------------------------------------------------------------- |
312 | | */ |
313 | | herr_t |
314 | | H5_timer_init(H5_timer_t *timer /*in,out*/) |
315 | 0 | { |
316 | 0 | assert(timer); |
317 | | |
318 | | /* Initialize everything */ |
319 | 0 | memset(timer, 0, sizeof(H5_timer_t)); |
320 | |
|
321 | 0 | return 0; |
322 | 0 | } /* end H5_timer_init() */ |
323 | | |
324 | | /*------------------------------------------------------------------------- |
325 | | * Function: H5_timer_start |
326 | | * |
327 | | * Purpose: Start tracking time in a platform-independent timer. |
328 | | * |
329 | | * Return: Success: 0 |
330 | | * Failure: -1 |
331 | | *------------------------------------------------------------------------- |
332 | | */ |
333 | | herr_t |
334 | | H5_timer_start(H5_timer_t *timer /*in,out*/) |
335 | 0 | { |
336 | 0 | assert(timer); |
337 | | |
338 | | /* Start the timer |
339 | | * This sets the "initial" times to the system-defined start times. |
340 | | */ |
341 | 0 | if (H5__timer_get_timevals(&(timer->initial)) < 0) |
342 | 0 | return -1; |
343 | | |
344 | 0 | timer->is_running = true; |
345 | |
|
346 | 0 | return 0; |
347 | 0 | } /* end H5_timer_start() */ |
348 | | |
349 | | /*------------------------------------------------------------------------- |
350 | | * Function: H5_timer_stop |
351 | | * |
352 | | * Purpose: Stop tracking time in a platform-independent timer. |
353 | | * |
354 | | * Return: Success: 0 |
355 | | * Failure: -1 |
356 | | *------------------------------------------------------------------------- |
357 | | */ |
358 | | herr_t |
359 | | H5_timer_stop(H5_timer_t *timer /*in,out*/) |
360 | 0 | { |
361 | 0 | assert(timer); |
362 | | |
363 | | /* Stop the timer */ |
364 | 0 | if (H5__timer_get_timevals(&(timer->final_interval)) < 0) |
365 | 0 | return -1; |
366 | | |
367 | | /* The "final" times are stored as intervals (final - initial) |
368 | | * for more useful reporting to the user. |
369 | | */ |
370 | 0 | timer->final_interval.elapsed = timer->final_interval.elapsed - timer->initial.elapsed; |
371 | 0 | timer->final_interval.system = timer->final_interval.system - timer->initial.system; |
372 | 0 | timer->final_interval.user = timer->final_interval.user - timer->initial.user; |
373 | | |
374 | | /* Add the intervals to the elapsed time */ |
375 | 0 | timer->total.elapsed += timer->final_interval.elapsed; |
376 | 0 | timer->total.system += timer->final_interval.system; |
377 | 0 | timer->total.user += timer->final_interval.user; |
378 | |
|
379 | 0 | timer->is_running = false; |
380 | |
|
381 | 0 | return 0; |
382 | 0 | } /* end H5_timer_stop() */ |
383 | | |
384 | | /*------------------------------------------------------------------------- |
385 | | * Function: H5_timer_get_times |
386 | | * |
387 | | * Purpose: Get the system, user and elapsed times from a timer. These |
388 | | * are the times since the timer was last started and will be |
389 | | * 0.0 in a timer that has not been started since it was |
390 | | * initialized. |
391 | | * |
392 | | * This function can be called either before or after |
393 | | * H5_timer_stop() has been called. If it is called before the |
394 | | * stop function, the timer will continue to run. |
395 | | * |
396 | | * The system and user times will be -1.0 if those times cannot |
397 | | * be computed on a particular platform. The elapsed time will |
398 | | * always be present. |
399 | | * |
400 | | * Return: Success: 0 |
401 | | * Failure: -1 |
402 | | *------------------------------------------------------------------------- |
403 | | */ |
404 | | herr_t |
405 | | H5_timer_get_times(H5_timer_t timer, H5_timevals_t *times /*in,out*/) |
406 | 0 | { |
407 | 0 | assert(times); |
408 | |
|
409 | 0 | if (timer.is_running) { |
410 | 0 | H5_timevals_t now; |
411 | | |
412 | | /* Get the current times and report the current intervals without |
413 | | * stopping the timer. |
414 | | */ |
415 | 0 | if (H5__timer_get_timevals(&now) < 0) |
416 | 0 | return -1; |
417 | | |
418 | 0 | times->elapsed = now.elapsed - timer.initial.elapsed; |
419 | 0 | times->system = now.system - timer.initial.system; |
420 | 0 | times->user = now.user - timer.initial.user; |
421 | 0 | } |
422 | 0 | else { |
423 | 0 | times->elapsed = timer.final_interval.elapsed; |
424 | 0 | times->system = timer.final_interval.system; |
425 | 0 | times->user = timer.final_interval.user; |
426 | 0 | } |
427 | | |
428 | 0 | return 0; |
429 | 0 | } /* end H5_timer_get_times() */ |
430 | | |
431 | | /*------------------------------------------------------------------------- |
432 | | * Function: H5_timer_get_total_times |
433 | | * |
434 | | * Purpose: Get the TOTAL system, user and elapsed times recorded by |
435 | | * the timer since its initialization. This is the sum of all |
436 | | * times recorded while the timer was running. |
437 | | * |
438 | | * These will be 0.0 in a timer that has not been started |
439 | | * since it was initialized. Calling H5_timer_init() on a |
440 | | * timer will reset these values to 0.0. |
441 | | * |
442 | | * This function can be called either before or after |
443 | | * H5_timer_stop() has been called. If it is called before the |
444 | | * stop function, the timer will continue to run. |
445 | | * |
446 | | * The system and user times will be -1.0 if those times cannot |
447 | | * be computed on a particular platform. The elapsed time will |
448 | | * always be present. |
449 | | * |
450 | | * Return: Success: 0 |
451 | | * Failure: -1 |
452 | | *------------------------------------------------------------------------- |
453 | | */ |
454 | | herr_t |
455 | | H5_timer_get_total_times(H5_timer_t timer, H5_timevals_t *times /*in,out*/) |
456 | 0 | { |
457 | 0 | assert(times); |
458 | |
|
459 | 0 | if (timer.is_running) { |
460 | 0 | H5_timevals_t now; |
461 | | |
462 | | /* Get the current times and report the current totals without |
463 | | * stopping the timer. |
464 | | */ |
465 | 0 | if (H5__timer_get_timevals(&now) < 0) |
466 | 0 | return -1; |
467 | | |
468 | 0 | times->elapsed = timer.total.elapsed + (now.elapsed - timer.initial.elapsed); |
469 | 0 | times->system = timer.total.system + (now.system - timer.initial.system); |
470 | 0 | times->user = timer.total.user + (now.user - timer.initial.user); |
471 | 0 | } |
472 | 0 | else { |
473 | 0 | times->elapsed = timer.total.elapsed; |
474 | 0 | times->system = timer.total.system; |
475 | 0 | times->user = timer.total.user; |
476 | 0 | } |
477 | | |
478 | 0 | return 0; |
479 | 0 | } /* end H5_timer_get_total_times() */ |
480 | | |
481 | | /*------------------------------------------------------------------------- |
482 | | * Function: H5_timer_get_time_string |
483 | | * |
484 | | * Purpose: Converts a time (in seconds) into a human-readable string |
485 | | * suitable for log messages. |
486 | | * |
487 | | * Return: Success: The time string. |
488 | | * |
489 | | * The general format of the time string is: |
490 | | * |
491 | | * "N/A" time < 0 (invalid time) |
492 | | * "%.f ns" time < 1 microsecond |
493 | | * "%.1f us" time < 1 millisecond |
494 | | * "%.1f ms" time < 1 second |
495 | | * "%.2f s" time < 1 minute |
496 | | * "%.f m %.f s" time < 1 hour |
497 | | * "%.f h %.f m %.f s" longer times |
498 | | * |
499 | | * Failure: NULL |
500 | | *------------------------------------------------------------------------- |
501 | | */ |
502 | | char * |
503 | | H5_timer_get_time_string(double seconds) |
504 | 0 | { |
505 | 0 | char *s; /* output string */ |
506 | | |
507 | | /* Used when the time is greater than 59 seconds */ |
508 | 0 | double days = 0.0; |
509 | 0 | double hours = 0.0; |
510 | 0 | double minutes = 0.0; |
511 | 0 | double remainder_sec = 0.0; |
512 | | |
513 | | /* Extract larger time units from count of seconds */ |
514 | 0 | if (seconds > 60.0) { |
515 | | /* Set initial # of seconds */ |
516 | 0 | remainder_sec = seconds; |
517 | | |
518 | | /* Extract days */ |
519 | 0 | days = floor(remainder_sec / H5_SEC_PER_DAY); |
520 | 0 | remainder_sec -= (days * H5_SEC_PER_DAY); |
521 | | |
522 | | /* Extract hours */ |
523 | 0 | hours = floor(remainder_sec / H5_SEC_PER_HOUR); |
524 | 0 | remainder_sec -= (hours * H5_SEC_PER_HOUR); |
525 | | |
526 | | /* Extract minutes */ |
527 | 0 | minutes = floor(remainder_sec / H5_SEC_PER_MIN); |
528 | 0 | remainder_sec -= (minutes * H5_SEC_PER_MIN); |
529 | | |
530 | | /* The # of seconds left is in remainder_sec */ |
531 | 0 | } |
532 | | |
533 | | /* Allocate */ |
534 | 0 | if (NULL == (s = (char *)calloc(H5TIMER_TIME_STRING_LEN, sizeof(char)))) |
535 | 0 | return NULL; |
536 | | |
537 | | /* Do we need a format string? Some people might like a certain |
538 | | * number of milliseconds or s before spilling to the next highest |
539 | | * time unit. Perhaps this could be passed as an integer. |
540 | | * (name? round_up_size? ?) |
541 | | */ |
542 | 0 | if (seconds < 0.0) |
543 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "N/A"); |
544 | 0 | else if (H5_DBL_ABS_EQUAL(0.0, seconds)) |
545 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "0.0 s"); |
546 | 0 | else if (seconds < 1.0E-6) |
547 | | /* t < 1 us, Print time in ns */ |
548 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.f ns", seconds * 1.0E9); |
549 | 0 | else if (seconds < 1.0E-3) |
550 | | /* t < 1 ms, Print time in us */ |
551 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.1f us", seconds * 1.0E6); |
552 | 0 | else if (seconds < 1.0) |
553 | | /* t < 1 s, Print time in ms */ |
554 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.1f ms", seconds * 1.0E3); |
555 | 0 | else if (seconds < H5_SEC_PER_MIN) |
556 | | /* t < 1 m, Print time in s */ |
557 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.2f s", seconds); |
558 | 0 | else if (seconds < H5_SEC_PER_HOUR) |
559 | | /* t < 1 h, Print time in m and s */ |
560 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.f m %.f s", minutes, remainder_sec); |
561 | 0 | else if (seconds < H5_SEC_PER_DAY) |
562 | | /* t < 1 d, Print time in h, m and s */ |
563 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.f h %.f m %.f s", hours, minutes, remainder_sec); |
564 | 0 | else |
565 | | /* Print time in d, h, m and s */ |
566 | 0 | snprintf(s, H5TIMER_TIME_STRING_LEN, "%.f d %.f h %.f m %.f s", days, hours, minutes, remainder_sec); |
567 | |
|
568 | 0 | return s; |
569 | 0 | } /* end H5_timer_get_time_string() */ |