my_getsystime.c 6.46 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2004 MySQL AB
unknown's avatar
unknown committed
2 3 4

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* get time since epoc in 100 nanosec units */
/* thus to get the current time we should use the system function
   with the highest possible resolution */

20 21 22 23 24
/* 
   TODO: in functions my_micro_time() and my_micro_time_and_time() there
   exists some common code that should be merged into a function.
*/

25 26 27
#include "mysys_priv.h"
#include "my_static.h"

28 29 30 31
#ifdef __NETWARE__
#include <nks/time.h>
#endif

unknown's avatar
unknown committed
32 33 34 35 36 37 38
ulonglong my_getsystime()
{
#ifdef HAVE_CLOCK_GETTIME
  struct timespec tp;
  clock_gettime(CLOCK_REALTIME, &tp);
  return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100;
#elif defined(__WIN__)
39
  LARGE_INTEGER t_cnt;
40
  if (query_performance_frequency)
41
  {
unknown's avatar
unknown committed
42
    QueryPerformanceCounter(&t_cnt);
43 44 45
    return ((t_cnt.QuadPart / query_performance_frequency * 10000000) +
            (t_cnt.QuadPart % query_performance_frequency * 10000000 /
             query_performance_frequency) + query_performance_offset);
46
  }
47
  return 0;
48 49 50 51
#elif defined(__NETWARE__)
  NXTime_t tm;
  NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm);
  return (ulonglong)tm/100;
unknown's avatar
unknown committed
52 53 54 55 56 57 58
#else
  /* TODO: check for other possibilities for hi-res timestamping */
  struct timeval tv;
  gettimeofday(&tv,NULL);
  return (ulonglong)tv.tv_sec*10000000+(ulonglong)tv.tv_usec*10;
#endif
}
59 60 61 62 63 64 65 66 67 68 69 70 71


/*
  Return current time

  SYNOPSIS
    my_time()
    flags	If MY_WME is set, write error if time call fails

*/

time_t my_time(myf flags __attribute__((unused)))
{
72
  time_t t;
73
#ifdef HAVE_GETHRTIME
74 75
  (void) my_micro_time_and_time(&t);
  return t;
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
#else
  /* The following loop is here beacuse time() may fail on some systems */
  while ((t= time(0)) == (time_t) -1)
  {
    if (flags & MY_WME)
      fprintf(stderr, "%s: Warning: time() call failed\n", my_progname);
  }
  return t;
#endif
}


/*
  Return time in micro seconds

  SYNOPSIS
    my_micro_time()

  NOTES
    This function is to be used to measure performance in micro seconds.
    As it's not defined whats the start time for the clock, this function
    us only useful to measure time between two moments.

    For windows platforms we need the frequency value of the CUP. This is
    initalized in my_init.c through QueryPerformanceFrequency().

    If Windows platform doesn't support QueryPerformanceFrequency() we will
    obtain the time via GetClockCount, which only supports milliseconds.

  RETURN
    Value in microseconds from some undefined point in time
*/

ulonglong my_micro_time()
{
  ulonglong newtime;
#if defined(__WIN__)
  if (query_performance_frequency)
  {
115
    QueryPerformanceCounter((LARGE_INTEGER*) &newtime);
unknown's avatar
unknown committed
116 117
    return ((newtime / query_performance_frequency * 10000000) +
            (newtime % query_performance_frequency * 10000000 /
118
             query_performance_frequency));
119 120
  }
  else
121
    newtime= (GetTickCount() * 1000); /* GetTickCount only returns millisec */
122
  return newtime;
123 124 125 126
#elif defined(HAVE_GETHRTIME)
  return gethrtime()/1000;
#else
  struct timeval t;
127 128 129
  /*
    The following loop is here because gettimeofday may fail on some systems
  */
130 131 132 133
  while (gettimeofday(&t, NULL) != 0)
  {}
  newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
  return newtime;
134
#endif  /* defined(__WIN__) */
135 136 137 138
}


/*
139
  Return time in seconds and timer in microseconds (not different start!)
140 141 142

  SYNOPSIS
    my_micro_time_and_time()
143 144
    time_arg		Will be set to seconds since epoch (00:00:00 UTC,
                        January 1, 1970)
145 146 147

  NOTES
    This function is to be useful when we need both the time and microtime.
148 149
    For example in MySQL this is used to get the query time start of a query
    and to measure the time of a query (for the slow query log)
150 151

  IMPLEMENTATION
152
    Value of time is as in time() call.
153 154
    Value of microtime is same as my_micro_time(), which may be totally
    unrealated to time()
155 156 157 158 159

  RETURN
    Value in microseconds from some undefined point in time
*/

160 161
#define DELTA_FOR_SECONDS LL(500000000)  /* Half a second */

162 163 164 165 166 167
ulonglong my_micro_time_and_time(time_t *time_arg)
{
  ulonglong newtime;
#if defined(__WIN__)
  if (query_performance_frequency)
  {
168
    QueryPerformanceCounter((LARGE_INTEGER*) &newtime);
169 170 171
    return ((newtime / query_performance_frequency * 10000000) +
            (newtime % query_performance_frequency * 10000000 /
             query_performance_frequency));
172 173
  }
  else
174
    newtime= (GetTickCount() * 1000); /* GetTickCount only returns millisec. */
175
  (void) time(time_arg);
176 177 178
  return newtime;
#elif defined(HAVE_GETHRTIME)
  /*
179 180
    Solaris has a very slow time() call. We optimize this by using the very
    fast gethrtime() call and only calling time() every 1/2 second
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
  */
  static hrtime_t prev_gethrtime= 0;
  static time_t cur_time= 0;
  hrtime_t cur_gethrtime;

  pthread_mutex_lock(&THR_LOCK_time);
  cur_gethrtime= gethrtime();
  if ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS)
  {
    cur_time= time(0);
    prev_gethrtime= cur_gethrtime;
  }
  *time_arg= cur_time;
  pthread_mutex_unlock(&THR_LOCK_time);
  return cur_gethrtime/1000;
196 197
#else
  struct timeval t;
198 199 200
  /*
    The following loop is here because gettimeofday may fail on some systems
  */
201 202 203 204 205
  while (gettimeofday(&t, NULL) != 0)
  {}
  *time_arg= t.tv_sec;
  newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
  return newtime;
206
#endif  /* defined(__WIN__) */
207 208 209 210 211 212 213 214 215 216 217 218
}


/*
  Returns current time

  SYNOPSIS
    my_time_possible_from_micro()
    microtime		Value from very recent my_micro_time()

  NOTES
    This function returns the current time. The microtime argument is only used
219 220
    if my_micro_time() uses a function that can safely be converted to the
    current time.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

  RETURN
    current time
*/

time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused)))
{
#if defined(__WIN__)
  time_t t;
  while ((t= time(0)) == (time_t) -1)
  {}
  return t;
#elif defined(HAVE_GETHRTIME)
  return my_time(0);                            /* Cached time */
#else
  return (time_t) (microtime / 1000000);
#endif  /* defined(__WIN__) */
}