What should I use to replace gettimeofday() on Windows? [duplicate]
Asked Answered
C

4

22

I'm writing a portable Socket class that supports timeouts for both sending and receiving... To implement these timeouts I'm using select().... But, I sometimes need to know how long I was blocked inside select() which of course on Linux I would implement by calling gettimeofday() before and after I call select() and then using timersub() to calculate the delta...

Given that select() on Windows accepts struct timeval for it's timeout, what method should I used to replace gettimeofday() on Windows?

Cima answered 4/11, 2009 at 19:26 Comment(0)
C
24

I ended up finding this page: gettimeofday() function for Windows (now via the Wayback Machine) which has a handy, dandy implementation of gettimeofday() on Windows. It uses the GetSystemTimeAsFileTime() method to get an accurate clock.

Update: Here's an alternative active link from the 'Unix to Windows Porting Dictionary for HPC' gettimeofday() (now via the Wayback Machine) that points to the implementation the OP referred to. Note also that there's a typo in the linked implementation:

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64 // WRONG
#else
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL // WRONG
#endif

The values shown are missing an extra 0 at the end (they assumed microseconds, not the number of 100-nanosecond intervals). This typo was found via this comment on a Google code project page. The correct values to use are shown below:

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_EPOCH_IN_MICROSECS  116444736000000000Ui64 // CORRECT
#else
  #define DELTA_EPOCH_IN_MICROSECS  116444736000000000ULL // CORRECT
#endif

PostgreSQL's implementation of gettimeofday for Windows:

/*
 * gettimeofday.c
 *    Win32 gettimeofday() replacement
 *
 * src/port/gettimeofday.c
 *
 * Copyright (c) 2003 SRA, Inc.
 * Copyright (c) 2003 SKC, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose, without fee, and without a
 * written agreement is hereby granted, provided that the above
 * copyright notice and this paragraph and the following two
 * paragraphs appear in all copies.
 *
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
 * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

#include "c.h"

#include <sys/time.h>


/* FILETIME of Jan 1 1970 00:00:00. */
static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL);

/*
 * timezone information is stored outside the kernel so tzp isn't used anymore.
 *
 * Note: this function is not for Win32 high precision timing purpose. See
 * elapsed_time().
 */
int
gettimeofday(struct timeval * tp, struct timezone * tzp)
{
    FILETIME    file_time;
    SYSTEMTIME  system_time;
    ULARGE_INTEGER ularge;

    GetSystemTime(&system_time);
    SystemTimeToFileTime(&system_time, &file_time);
    ularge.LowPart = file_time.dwLowDateTime;
    ularge.HighPart = file_time.dwHighDateTime;

    tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
    tp->tv_usec = (long) (system_time.wMilliseconds * 1000);

    return 0;
}
Cima answered 5/11, 2009 at 1:17 Comment(5)
Here is a link to the relevant code from PostgreSQL: git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/port/…Angilaangina
I'm sure this is a stupid question, but I can't find an answer: where do I find c.h?Anecdotist
Note that this function breaks after 2038. The fix is to ensure the type of timespec.tv_sec is NOT long but a 64bit one (like uint64_t), and remove the cast to long in the last two lines.Autogiro
"where do I find c.h?" I fixed the headers so that it will compile on Windows as written. c.h wasn't necessary and another header mentioned doesn't exist on Windows, while a necessary header was left out. It's all good now though.Rausch
why do i get a negativeStandstill
T
4

How about:

unsigned long start = GetTickCount();
// stuff that needs to be timed
unsigned long delta = GetTickCount() - start;

GetTickCount() is not very precise, but will probably work well. If you see a lot of 0, 16 or 31 millisecond intervals, try timing over longer intervals or use a more precise function like timeGetTime.

What I usually do is this:

unsigned long deltastack;
int samples = 0;
float average;

unsigned long start = GetTickCount();
// stuff that needs to be timed
unsigned long delta = GetTickCount() - start;

deltastack += delta;
if (samples++ == 10)
{
   // total time divided by amount of samples
   average = (float)deltastack / 10.f;
   deltastack = 0;
   samples = 0;  
}
Tourane answered 4/11, 2009 at 20:30 Comment(3)
GetTicksCount rollover every ~45.7 days.Dewan
@Shay: When have you seen Windows up for over 45 days straight? OK, yes that was uncalled for...Xerophilous
GetTickCount function - Retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days.Ouphe
D
1

In your case I would use the platform independent std::clock

Dewan answered 4/11, 2009 at 21:8 Comment(2)
This function does not return an absolute time reference.Vermiculite
@Vermiculite he didn't say he needs an absolute time referenceDewan
T
1

You can check out QueryPerformanceCounter and QueryPerformanceFrequency. These are very high resolution- down to one tick per ten cycles on some hardware- timers.

Tillie answered 5/6, 2012 at 22:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.