4

I'm trying to use 2 different equivalents for UNIX's gettimeofday() function on Windows, using Visual Studio 2013.

I took the first one from here. As the second one, I'm using the _ftime64_s function, as explained here.

They work, but not as I expected. I want to get different values when printing the seconds, or at least the milliseconds, but I get the same value for the printings with gettimeofday() (mytime1 & mytime2) and with _ftime64_s (mytime3 & mytime4).

However, it worth mentioning that the value of the milliseconds is indeed different between these two functions (that is, the milliseconds value of mytime1/mytime2 is different from mytime3/mytime4).

Here's my code:

#include <stdio.h>
#include <Windows.h>
#include <stdint.h>
#include <sys/timeb.h>
#include <time.h>

#define WIN32_LEAN_AND_MEAN

int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
    // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
    static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);

    SYSTEMTIME  system_time;
    FILETIME    file_time;
    uint64_t    time;

    GetSystemTime(&system_time);
    SystemTimeToFileTime(&system_time, &file_time);
    time = ((uint64_t)file_time.dwLowDateTime);
    time += ((uint64_t)file_time.dwHighDateTime) << 32;

    tp->tv_sec = (long)((time - EPOCH) / 10000000L);
    tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
    return 0;
}

int main()
{
    /* working with struct timeval and gettimeofday equivalent */

    struct timeval mytime1;
    struct timeval mytime2;

    gettimeofday(&(mytime1), NULL);
    gettimeofday(&(mytime2), NULL);

    printf("Seconds: %d\n", (int)(mytime1.tv_sec));
    printf("Milliseconds: %d\n", (int)(mytime1.tv_usec));

    printf("Seconds: %d\n", (int)(mytime2.tv_sec));
    printf("Milliseconds: %d\n", (int)(mytime2.tv_usec));

    /* working with _ftime64_s */

    struct _timeb mytime3;
    struct _timeb mytime4;

    _ftime64_s(&mytime3);
    _ftime64_s(&mytime4);

    printf("Seconds: %d\n", mytime3.time);
    printf("Milliseconds: %d\n", mytime3.millitm);

    printf("Seconds: %d\n", mytime4.time);
    printf("Milliseconds: %d\n", mytime4.millitm);

    return (0);
}

I tried other format specifiers (%f, %lu) and castings ((float), (double), (long), (size_t)), but it didn't matter. Suggestions will be welcomed.

Community
  • 1
  • 1
OfirD
  • 9,442
  • 5
  • 47
  • 90
  • The `tv_usec` member of `struct timeval` is *micro*seconds, not milliseconds like the `millitm` member of `struct _timeb` or `struct __timeb64`... so you need to divide by 1000 to get milliseconds. Also, shouldn't you use `struct __timeb64` with `_ftime64_s` or `struct _timeb` with `_ftime_s`? – Dmitri Jan 16 '16 at 20:09
  • You seem to be asking why a function takes a different amount of time on two different OSs. That would all be a matter of opinion. – user3629249 Jan 16 '16 at 20:56
  • Also, why would you expect the times to be different when you're calling the functions so close together? Your whole program probably finishes in well under one second, so it's no surprise if all four calls give the same time in seconds (and maybe even milliseconds) most of the time. If you want different times, add a delay between calls. – Dmitri Jan 16 '16 at 22:46

1 Answers1

3

QueryPerformanceCounter is used for accurate timing on windows. Usage can be as follows:

uint64_t microseconds()
{
    LARGE_INTEGER fq, t;
    QueryPerformanceFrequency(&fq);
    QueryPerformanceCounter(&t);
    return (1000000 * t.QuadPart) / fq.QuadPart;
}

This does not work with any EPOCH as far as I know. For that you need GetSystemTimePreciseAsFileTime which is only available on Windows 8 and higher.

uint64_t MyGetSystemTimePreciseAsFileTime()
{
    HMODULE lib = LoadLibraryW(L"kernel32.dll");
    if (!lib) return 0;
    FARPROC fp = GetProcAddress(lib, "GetSystemTimePreciseAsFileTime");
    ULARGE_INTEGER largeInt;
    largeInt.QuadPart = 0;
    if (fp)
    {
        T_GetSystemTimePreciseAsFileTime* pfn = (T_GetSystemTimePreciseAsFileTime*)fp;
        FILETIME fileTime = { 0 };
        pfn(&fileTime);
        largeInt.HighPart = fileTime.dwHighDateTime;
        largeInt.LowPart = fileTime.dwLowDateTime;
    }
    FreeLibrary(lib);
    return largeInt.QuadPart;
}

int main()
{
    uint64_t t1 = microseconds();
    uint64_t t2 = microseconds();
    printf("t1: %llu\n", t1);
    printf("t2: %llu\n", t2);
    return (0);
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77