GetTime.c 4.46 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team 2005
 *
 * Machine-dependent time measurement functions
 *
 * ---------------------------------------------------------------------------*/

#include "Rts.h"
#include "GetTime.h"

#include <windows.h>

14 15 16 17
#ifdef HAVE_TIME_H
# include <time.h>
#endif

18 19
/* Convert FILETIMEs into secs */

Simon Marlow's avatar
Simon Marlow committed
20 21
static INLINE_ME Time
fileTimeToRtsTime(FILETIME ft)
22
{
Simon Marlow's avatar
Simon Marlow committed
23 24 25 26
    Time t;
    t = ((Time)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
    t = NSToTime(t * 100);
    /* FILETIMES are in units of 100ns */
27 28
    return t;
}    
29

30
void
Simon Marlow's avatar
Simon Marlow committed
31
getProcessTimes(Time *user, Time *elapsed)
32 33 34 35 36
{
    *user    = getProcessCPUTime();
    *elapsed = getProcessElapsedTime();
}

Simon Marlow's avatar
Simon Marlow committed
37
Time
38 39 40 41 42 43 44
getProcessCPUTime(void)
{
    FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};

    if (!GetProcessTimes(GetCurrentProcess(), &creationTime,
			 &exitTime, &kernelTime, &userTime)) {
	return 0;
45
    }
46

Simon Marlow's avatar
Simon Marlow committed
47
    return fileTimeToRtsTime(userTime);
48 49
}

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
// Number of ticks per second used by the QueryPerformanceFrequency
// implementaiton, represented by a 64-bit union type.
static LARGE_INTEGER qpc_frequency = {.QuadPart = 0};

// Initialize qpc_frequency. This function should be called before any call to
// getMonotonicNSec.  If QPC is not supported on this system, qpc_frequency is
// set to 0.
void initializeTimer()
{
    BOOL qpc_supported = QueryPerformanceFrequency(&qpc_frequency);
    if (!qpc_supported)
    {
        qpc_frequency.QuadPart = 0;
    }
}

HsWord64
getMonotonicNSec()
{
    if (qpc_frequency.QuadPart)
    {
        // system_time is a 64-bit union type used to represent the
        // tick count returned by QueryPerformanceCounter
        LARGE_INTEGER system_time;

        // get the tick count.
        QueryPerformanceCounter(&system_time);

        // compute elapsed seconds as double
        double secs = (double)system_time.QuadPart /
                      (double)qpc_frequency.QuadPart;

        // return elapsed time in nanoseconds
        return (HsWord64)(secs * 1e9);
    }
    else // fallback to GetTickCount
    {
        // NOTE: GetTickCount is a 32-bit millisecond value, so it wraps around
        // every 49 days.
        DWORD count = GetTickCount();

        // getTickCount is in milliseconds, so multiply it by 1000000 to get
        // nanoseconds.
        return (HsWord64)count * 1000000;
    }
}
96

Simon Marlow's avatar
Simon Marlow committed
97
Time
98
getProcessElapsedTime(void)
99
{
100
    return NSToTime(getMonotonicNSec());
101 102
}

Simon Marlow's avatar
Simon Marlow committed
103
Time
104
getThreadCPUTime(void)
105
{
106 107 108 109 110 111 112
    FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};

    if (!GetThreadTimes(GetCurrentThread(), &creationTime,
			&exitTime, &kernelTime, &userTime)) {
	return 0;
    }

Simon Marlow's avatar
Simon Marlow committed
113
    return fileTimeToRtsTime(userTime);
114 115
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
void
getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
{
    /* Windows has a bunch of time APIs but none that directly give
       us unix epoch time, so we have to do a little dance. */

    SYSTEMTIME systime;
    FILETIME filetime;
    ULARGE_INTEGER unixtime;

    /* Windows SYSTEMTIME is a big struct with fields for
       year, month, day, hour, minute, second, millisecond. */
    GetSystemTime(&systime);
    /* Windows FILETIME timestamps use an epoch-based time,
       using a 64bit unsigned word. The time is measured in
       units of 100 nanoseconds since an epoch of 1601. */
    SystemTimeToFileTime(&systime, &filetime);

    /* FILETIME isn't directly a 64bit word, but a struct with
       a pair of 32bit words, so we have to convert via a
       ULARGE_INTEGER struct which is a handy union type */
    unixtime.LowPart  = filetime.dwLowDateTime;
    unixtime.HighPart = filetime.dwHighDateTime;
    
    /* We have to do an epoch conversion, since FILETIME uses 1601
       while we want unix epoch of 1970. In case you were wondering,
       there were 11,644,473,600 seconds between 1601 and 1970, then
       multiply by 10^7 for units of 100 nanoseconds. */
    unixtime.QuadPart = unixtime.QuadPart - 116444736000000000ull;
    
    /* For the seconds part we use integer division by 10^7 */
    *sec  = unixtime.QuadPart / 10000000ull;
    
    /* The remainder from integer division by 10^7 gives us
       the sub-second component in units of 100 nanoseconds.
       So for nanoseconds we just multiply by 100.
       Note that nanoseconds always fits in a 32bit word */
    *nsec = ((unsigned long)(unixtime.QuadPart % 10000000ull)) * 100ul;
}

156 157
nat
getPageFaults(void)
158 159 160 161 162
{
  /* ToDo (on NT): better, get this via the performance data
     that's stored in the registry. */
    return 0;
}