monoclock.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include <sys/time.h>
  2. #include <errno.h>
  3. #include <time.h>
  4. #include "warnp.h"
  5. #include "monoclock.h"
  6. /* Determine which clock(s) to use. */
  7. #ifndef POSIXFAIL_CLOCK_GETTIME
  8. #ifdef CLOCK_MONOTONIC
  9. #define USE_MONOTONIC
  10. #endif
  11. #ifndef POSIXFAIL_CLOCK_REALTIME
  12. #define USE_REALTIME
  13. #endif
  14. #endif
  15. /**
  16. * monoclock_get(tv):
  17. * Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use
  18. * that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if
  19. * available) or gettimeofday(2).
  20. */
  21. int
  22. monoclock_get(struct timeval * tv)
  23. {
  24. #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
  25. struct timespec tp;
  26. #endif
  27. #ifdef USE_MONOTONIC
  28. if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
  29. tv->tv_sec = tp.tv_sec;
  30. tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
  31. } else if ((errno != ENOSYS) && (errno != EINVAL)) {
  32. warnp("clock_gettime(CLOCK_MONOTONIC)");
  33. goto err0;
  34. } else
  35. #endif
  36. #ifdef USE_REALTIME
  37. if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
  38. tv->tv_sec = tp.tv_sec;
  39. tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
  40. } else {
  41. warnp("clock_gettime(CLOCK_REALTIME)");
  42. goto err0;
  43. }
  44. #else
  45. if (gettimeofday(tv, NULL)) {
  46. warnp("gettimeofday");
  47. goto err0;
  48. }
  49. #endif
  50. /* Success! */
  51. return (0);
  52. err0:
  53. /* Failure! */
  54. return (-1);
  55. }
  56. /**
  57. * monoclock_get_cputime(tv):
  58. * Store in ${tv} the duration the process has been running if
  59. * CLOCK_PROCESS_CPUTIME_ID is available; fall back to monoclock_get()
  60. * otherwise.
  61. */
  62. int
  63. monoclock_get_cputime(struct timeval * tv)
  64. {
  65. /* Use CLOCK_PROCESS_CPUTIME_ID if available. */
  66. #ifdef CLOCK_PROCESS_CPUTIME_ID
  67. struct timespec tp;
  68. if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) == 0) {
  69. tv->tv_sec = tp.tv_sec;
  70. tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
  71. } else if ((errno != ENOSYS) && (errno != EINVAL)) {
  72. warnp("clock_gettime(CLOCK_PROCESS_CPUTIME_ID)");
  73. goto err0;
  74. } else
  75. #endif
  76. /* Fall back to monoclock_get(). */
  77. if (monoclock_get(tv))
  78. goto err0;
  79. /* Success! */
  80. return (0);
  81. err0:
  82. /* Failure! */
  83. return (-1);
  84. }
  85. /**
  86. * monoclock_getres(resd):
  87. * Store an upper limit on timer granularity in ${resd}. If CLOCK_MONOTONIC
  88. * is available, use that clock; if CLOCK_MONOTONIC is unavailable, use
  89. * CLOCK_REALTIME (if available) or gettimeofday(2). For this value to be
  90. * meaningful, we assume that clock_getres(x) succeeds iff clock_gettime(x)
  91. * succeeds.
  92. */
  93. int
  94. monoclock_getres(double * resd)
  95. {
  96. #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
  97. struct timespec res;
  98. #endif
  99. #ifdef USE_MONOTONIC
  100. if (clock_getres(CLOCK_MONOTONIC, &res) == 0) {
  101. /* Convert clock resolution to a double. */
  102. *resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
  103. } else if ((errno != ENOSYS) && (errno != EINVAL)) {
  104. warnp("clock_getres(CLOCK_MONOTONIC)");
  105. goto err0;
  106. } else
  107. #endif
  108. #ifdef USE_REALTIME
  109. if (clock_getres(CLOCK_REALTIME, &res) == 0) {
  110. /* Convert clock resolution to a double. */
  111. *resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
  112. } else {
  113. warnp("clock_getres(CLOCK_REALTIME)");
  114. goto err0;
  115. }
  116. #else
  117. /*
  118. * We'll be using gettimeofday(). There is no standard way of getting
  119. * the resolution of this clock, but it seems safe to assume that it
  120. * ticks at a minimum rate of CLOCKS_PER_SEC Hz (even though that is
  121. * defined in relation to the measurement of processor time usage, not
  122. * wallclock time); on non-broken systems we'll be relying on
  123. * clock_gettime and clock_getres anyway.
  124. */
  125. *resd = 1.0 / CLOCKS_PER_SEC;
  126. #endif
  127. /* Success! */
  128. return (0);
  129. #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
  130. err0:
  131. /* Failure! */
  132. return (-1);
  133. #endif
  134. }