summaryrefslogtreecommitdiff
path: root/rts/win32/GetTime.c
blob: 13fb5ab22d2ff8a63323f1eef50b976ec82d884f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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
/* -----------------------------------------------------------------------------
 *
 * (c) The GHC Team 2005
 *
 * Machine-dependent time measurement functions
 *
 * ---------------------------------------------------------------------------*/

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

#include <windows.h>

#ifdef HAVE_TIME_H
# include <time.h>
#endif

#define HNS_PER_SEC 10000000LL /* FILETIMES are in units of 100ns */
/* Convert FILETIMEs into secs */

static INLINE_ME Ticks
fileTimeToTicks(FILETIME ft)
{
    Ticks t;
    t = ((Ticks)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
    t = (t * TICKS_PER_SECOND) / HNS_PER_SEC;
    return t;
}    

void
getProcessTimes(Ticks *user, Ticks *elapsed)
{
    *user    = getProcessCPUTime();
    *elapsed = getProcessElapsedTime();
}

Ticks
getProcessCPUTime(void)
{
    FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};

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

    return fileTimeToTicks(userTime);
}

// getProcessElapsedTime relies on QueryPerformanceFrequency 
// which should be available on any Windows computer thay you
// would want to run Haskell on. Satnam Singh, 5 July 2010.

Ticks
getProcessElapsedTime(void)
{
    // frequency represents the number of ticks per second
    // used by the QueryPerformanceFrequency implementaiton
    // and is represented by a 64-bit union type initially set to 0
    // and updated just once (hence use of static).
    static LARGE_INTEGER frequency = {.QuadPart = 0} ;  

    // system_time is a 64-bit union type used to represent the
    // tick count returned by QueryPerformanceCounter
    LARGE_INTEGER system_time ;

    // If this is the first time we are calling getProcessElapsedTime
    // then record the ticks per second used by QueryPerformanceCounter
    if (frequency.QuadPart == 0) {
      QueryPerformanceFrequency(&frequency);
    }
    
    // Get the tick count.
    QueryPerformanceCounter(&system_time) ;

    // Return the tick count as a millisecond value. 
    // Using double to compute the intermediate value, because a 64-bit
    // int would overflow when multiplied by TICKS_PER_SECOND in about 81 days.
    return (Ticks)((TICKS_PER_SECOND * (double)system_time.QuadPart) / (double)frequency.QuadPart) ;
}

Ticks
getThreadCPUTime(void)
{
    FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};

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

    return fileTimeToTicks(userTime);
}

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;
}

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