timing.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * StarPU
  3. * Copyright (C) INRIA 2008-2010 (see AUTHORS file)
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published by
  7. * the Free Software Foundation; either version 2.1 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. *
  14. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  15. */
  16. #include "timing.h"
  17. #ifdef HAVE_CLOCK_GETTIME
  18. #include <time.h>
  19. #ifndef _POSIX_C_SOURCE
  20. /* for clock_gettime */
  21. #define _POSIX_C_SOURCE 199309L
  22. #endif
  23. #ifdef __linux__
  24. #ifndef CLOCK_MONOTONIC_RAW
  25. #define CLOCK_MONOTONIC_RAW 4
  26. #endif
  27. #endif
  28. static struct timespec reference_start_time_ts;
  29. /* Modern CPUs' clocks are usually not synchronized so we use a monotonic clock
  30. * to have consistent timing measurements. The CLOCK_MONOTONIC_RAW clock is not
  31. * subject to NTP adjustments, but is not available on all systems (in that
  32. * case we use the CLOCK_MONOTONIC clock instead). */
  33. void __starpu_clock_gettime(struct timespec *ts) {
  34. #ifdef CLOCK_MONOTONIC_RAW
  35. static int raw_supported = 0;
  36. switch (raw_supported) {
  37. case -1:
  38. break;
  39. case 1:
  40. clock_gettime(CLOCK_MONOTONIC_RAW, ts);
  41. return;
  42. case 0:
  43. if (clock_gettime(CLOCK_MONOTONIC_RAW, ts)) {
  44. raw_supported = -1;
  45. break;
  46. } else {
  47. raw_supported = 1;
  48. return;
  49. }
  50. }
  51. #endif
  52. clock_gettime(CLOCK_MONOTONIC, ts);
  53. }
  54. void _starpu_timing_init(void)
  55. {
  56. __starpu_clock_gettime(&reference_start_time_ts);
  57. }
  58. void starpu_clock_gettime(struct timespec *ts)
  59. {
  60. struct timespec absolute_ts;
  61. /* Read the current time */
  62. __starpu_clock_gettime(&absolute_ts);
  63. /* Compute the relative time since initialization */
  64. _starpu_timespec_sub(&absolute_ts, &reference_start_time_ts, ts);
  65. }
  66. #else // !HAVE_CLOCK_GETTIME
  67. #if defined(__i386__) || defined(__pentium__) || defined(__pentiumpro__) || defined(__i586__) || defined(__i686__) || defined(__k6__) || defined(__k7__) || defined(__x86_64__)
  68. typedef union starpu_u_tick
  69. {
  70. uint64_t tick;
  71. struct
  72. {
  73. uint32_t low;
  74. uint32_t high;
  75. }
  76. sub;
  77. } starpu_tick_t;
  78. #define STARPU_GET_TICK(t) __asm__ volatile("rdtsc" : "=a" ((t).sub.low), "=d" ((t).sub.high))
  79. #define TICK_RAW_DIFF(t1, t2) ((t2).tick - (t1).tick)
  80. #define TICK_DIFF(t1, t2) (TICK_RAW_DIFF(t1, t2) - residual)
  81. static starpu_tick_t reference_start_tick;
  82. static double scale = 0.0;
  83. static unsigned long long residual = 0;
  84. static int inited = 0;
  85. void _starpu_timing_init(void)
  86. {
  87. static starpu_tick_t t1, t2;
  88. int i;
  89. if (inited) return;
  90. residual = (unsigned long long)1 << 63;
  91. for(i = 0; i < 20; i++)
  92. {
  93. STARPU_GET_TICK(t1);
  94. STARPU_GET_TICK(t2);
  95. residual = STARPU_MIN(residual, TICK_RAW_DIFF(t1, t2));
  96. }
  97. {
  98. struct timeval tv1,tv2;
  99. STARPU_GET_TICK(t1);
  100. gettimeofday(&tv1,0);
  101. usleep(500000);
  102. STARPU_GET_TICK(t2);
  103. gettimeofday(&tv2,0);
  104. scale = ((tv2.tv_sec*1e6 + tv2.tv_usec) -
  105. (tv1.tv_sec*1e6 + tv1.tv_usec)) /
  106. (double)(TICK_DIFF(t1, t2));
  107. }
  108. STARPU_GET_TICK(reference_start_tick);
  109. inited = 1;
  110. }
  111. void starpu_clock_gettime(struct timespec *ts)
  112. {
  113. starpu_tick_t tick_now;
  114. STARPU_GET_TICK(tick_now);
  115. uint64_t elapsed_ticks = TICK_DIFF(reference_start_tick, tick_now);
  116. /* We convert this number into nano-seconds so that we can fill the
  117. * timespec structure. */
  118. uint64_t elapsed_ns = (uint64_t)(((double)elapsed_ticks)*(scale*1000.0));
  119. long tv_nsec = (elapsed_ns % 1000000000);
  120. time_t tv_sec = (elapsed_ns / 1000000000);
  121. ts->tv_sec = tv_sec;
  122. ts->tv_nsec = tv_nsec;
  123. }
  124. #else // !HAVE_CLOCK_GETTIME & no rdtsc
  125. #warning StarPU could not find a timer, clock will always return 0
  126. void _starpu_timing_init(void)
  127. {
  128. }
  129. void starpu_clock_gettime(struct timespec *ts)
  130. {
  131. timerclear(ts);
  132. }
  133. #endif
  134. #endif // HAVE_CLOCK_GETTIME
  135. /* Returns the time elapsed between start and end in microseconds */
  136. double _starpu_timing_timespec_delay_us(struct timespec *start, struct timespec *end)
  137. {
  138. struct timespec diff;
  139. _starpu_timespec_sub(end, start, &diff);
  140. double us = (diff.tv_sec*1e6) + (diff.tv_nsec*1e-3);
  141. return us;
  142. }
  143. double _starpu_timing_timespec_to_us(struct timespec *ts)
  144. {
  145. return (ts->tv_sec*1e6) + (ts->tv_nsec*1e-3);
  146. }
  147. double _starpu_timing_now(void)
  148. {
  149. struct timespec now;
  150. starpu_clock_gettime(&now);
  151. return _starpu_timing_timespec_to_us(&now);
  152. }