timing.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2009-2012 Université de Bordeaux 1
  4. * Copyright (C) 2010, 2011, 2012 Centre National de la Recherche Scientifique
  5. *
  6. * StarPU is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2.1 of the License, or (at
  9. * your option) any later version.
  10. *
  11. * StarPU is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. *
  15. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  16. */
  17. #include <sys/time.h>
  18. #include <starpu.h>
  19. #include <common/config.h>
  20. #include <profiling/profiling.h>
  21. #include <common/timing.h>
  22. #include <math.h>
  23. #ifdef STARPU_SIMGRID
  24. #include <msg/msg.h>
  25. #endif
  26. #ifdef STARPU_SIMGRID
  27. void _starpu_timing_init(void)
  28. {
  29. }
  30. void _starpu_clock_gettime(struct timespec *ts)
  31. {
  32. double now = MSG_get_clock();
  33. ts->tv_sec = floor(now);
  34. ts->tv_nsec = floor((now - ts->tv_sec) * 1000000000);
  35. }
  36. #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
  37. #include <time.h>
  38. #ifndef _POSIX_C_SOURCE
  39. /* for clock_gettime */
  40. #define _POSIX_C_SOURCE 199309L
  41. #endif
  42. #ifdef __linux__
  43. #ifndef CLOCK_MONOTONIC_RAW
  44. #define CLOCK_MONOTONIC_RAW 4
  45. #endif
  46. #endif
  47. static struct timespec _starpu_reference_start_time_ts;
  48. /* Modern CPUs' clocks are usually not synchronized so we use a monotonic clock
  49. * to have consistent timing measurements. The CLOCK_MONOTONIC_RAW clock is not
  50. * subject to NTP adjustments, but is not available on all systems (in that
  51. * case we use the CLOCK_MONOTONIC clock instead). */
  52. static void _starpu_clock_readtime(struct timespec *ts)
  53. {
  54. #ifdef CLOCK_MONOTONIC_RAW
  55. static int raw_supported = 0;
  56. switch (raw_supported)
  57. {
  58. case -1:
  59. break;
  60. case 1:
  61. clock_gettime(CLOCK_MONOTONIC_RAW, ts);
  62. return;
  63. case 0:
  64. if (clock_gettime(CLOCK_MONOTONIC_RAW, ts))
  65. {
  66. raw_supported = -1;
  67. break;
  68. }
  69. else
  70. {
  71. raw_supported = 1;
  72. return;
  73. }
  74. }
  75. #endif
  76. clock_gettime(CLOCK_MONOTONIC, ts);
  77. }
  78. void _starpu_timing_init(void)
  79. {
  80. _starpu_clock_gettime(&_starpu_reference_start_time_ts);
  81. }
  82. void _starpu_clock_gettime(struct timespec *ts)
  83. {
  84. struct timespec absolute_ts;
  85. /* Read the current time */
  86. _starpu_clock_readtime(&absolute_ts);
  87. /* Compute the relative time since initialization */
  88. starpu_timespec_sub(&absolute_ts, &_starpu_reference_start_time_ts, ts);
  89. }
  90. #else // !HAVE_CLOCK_GETTIME
  91. #if defined(__i386__) || defined(__pentium__) || defined(__pentiumpro__) || defined(__i586__) || defined(__i686__) || defined(__k6__) || defined(__k7__) || defined(__x86_64__)
  92. union starpu_u_tick
  93. {
  94. uint64_t tick;
  95. struct
  96. {
  97. uint32_t low;
  98. uint32_t high;
  99. }
  100. sub;
  101. };
  102. #define STARPU_GET_TICK(t) __asm__ volatile("rdtsc" : "=a" ((t).sub.low), "=d" ((t).sub.high))
  103. #define STARPU_TICK_RAW_DIFF(t1, t2) ((t2).tick - (t1).tick)
  104. #define STARPU_TICK_DIFF(t1, t2) (STARPU_TICK_RAW_DIFF(t1, t2) - _starpu_residual)
  105. static union starpu_u_tick _starpu_reference_start_tick;
  106. static double _starpu_scale = 0.0;
  107. static unsigned long long _starpu_residual = 0;
  108. static int _starpu_inited = 0;
  109. void _starpu_timing_init(void)
  110. {
  111. static union starpu_u_tick t1, t2;
  112. int i;
  113. if (_starpu_inited) return;
  114. _starpu_residual = (unsigned long long)1 << 63;
  115. for(i = 0; i < 20; i++)
  116. {
  117. STARPU_GET_TICK(t1);
  118. STARPU_GET_TICK(t2);
  119. _starpu_residual = STARPU_MIN(_starpu_residual, STARPU_TICK_RAW_DIFF(t1, t2));
  120. }
  121. {
  122. struct timeval tv1,tv2;
  123. STARPU_GET_TICK(t1);
  124. gettimeofday(&tv1,0);
  125. usleep(500000);
  126. STARPU_GET_TICK(t2);
  127. gettimeofday(&tv2,0);
  128. _starpu_scale = ((tv2.tv_sec*1e6 + tv2.tv_usec) -
  129. (tv1.tv_sec*1e6 + tv1.tv_usec)) /
  130. (double)(STARPU_TICK_DIFF(t1, t2));
  131. }
  132. STARPU_GET_TICK(_starpu_reference_start_tick);
  133. _starpu_inited = 1;
  134. }
  135. void _starpu_clock_gettime(struct timespec *ts)
  136. {
  137. union starpu_u_tick tick_now;
  138. STARPU_GET_TICK(tick_now);
  139. uint64_t elapsed_ticks = STARPU_TICK_DIFF(_starpu_reference_start_tick, tick_now);
  140. /* We convert this number into nano-seconds so that we can fill the
  141. * timespec structure. */
  142. uint64_t elapsed_ns = (uint64_t)(((double)elapsed_ticks)*(_starpu_scale*1000.0));
  143. long tv_nsec = (elapsed_ns % 1000000000);
  144. time_t tv_sec = (elapsed_ns / 1000000000);
  145. ts->tv_sec = tv_sec;
  146. ts->tv_nsec = tv_nsec;
  147. }
  148. #else // !HAVE_CLOCK_GETTIME & no rdtsc
  149. #warning StarPU could not find a timer, clock will always return 0
  150. void _starpu_timing_init(void)
  151. {
  152. }
  153. void _starpu_clock_gettime(struct timespec *ts)
  154. {
  155. timerclear(ts);
  156. }
  157. #endif
  158. #endif // HAVE_CLOCK_GETTIME
  159. /* Returns the time elapsed between start and end in microseconds */
  160. double starpu_timing_timespec_delay_us(struct timespec *start, struct timespec *end)
  161. {
  162. struct timespec diff;
  163. starpu_timespec_sub(end, start, &diff);
  164. double us = (diff.tv_sec*1e6) + (diff.tv_nsec*1e-3);
  165. return us;
  166. }
  167. double starpu_timing_timespec_to_us(struct timespec *ts)
  168. {
  169. return (1000000.0*ts->tv_sec) + (0.001*ts->tv_nsec);
  170. }
  171. double starpu_timing_now(void)
  172. {
  173. #ifdef STARPU_SIMGRID
  174. return MSG_get_clock()*1000000;
  175. #else
  176. struct timespec now;
  177. _starpu_clock_gettime(&now);
  178. return starpu_timing_timespec_to_us(&now);
  179. #endif
  180. }