[Profiler] Use the correct function to increment the refcount
[mono.git] / mono / utils / mono-time.c
1 /*
2  * Time utility functions.
3  * Author: Paolo Molaro (<lupus@ximian.com>)
4  * Copyright (C) 2008 Novell, Inc.
5  */
6
7 #include <config.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10
11 #ifdef HAVE_SYS_TIME_H
12 #include <sys/time.h>
13 #endif
14
15 #include <utils/mono-time.h>
16
17
18 #define MTICKS_PER_SEC 10000000
19
20 #ifdef HOST_WIN32
21 #include <windows.h>
22
23 guint32
24 mono_msec_ticks (void)
25 {
26         /* GetTickCount () is reportedly monotonic */
27         return GetTickCount ();
28 }
29
30 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
31 gint64
32 mono_100ns_ticks (void)
33 {
34         static LARGE_INTEGER freq;
35         static UINT64 start_time;
36         UINT64 cur_time;
37         LARGE_INTEGER value;
38
39         if (!freq.QuadPart) {
40                 if (!QueryPerformanceFrequency (&freq))
41                         return mono_100ns_datetime ();
42                 QueryPerformanceCounter (&value);
43                 start_time = value.QuadPart;
44         }
45         QueryPerformanceCounter (&value);
46         cur_time = value.QuadPart;
47         /* we use unsigned numbers and return the difference to avoid overflows */
48         return (cur_time - start_time) * (double)MTICKS_PER_SEC / freq.QuadPart;
49 }
50
51 /* Returns the number of 100ns ticks since Jan 1, 1601, UTC timezone */
52 gint64
53 mono_100ns_datetime (void)
54 {
55         ULARGE_INTEGER ft;
56
57         if (sizeof(ft) != sizeof(FILETIME))
58                 g_assert_not_reached ();
59
60         GetSystemTimeAsFileTime ((FILETIME*) &ft);
61         return ft.QuadPart;
62 }
63
64 #else
65
66
67 #if defined (HAVE_SYS_PARAM_H)
68 #include <sys/param.h>
69 #endif
70 #if defined(HAVE_SYS_SYSCTL_H)
71 #include <sys/sysctl.h>
72 #endif
73
74 #if defined(PLATFORM_MACOSX)
75 #include <mach/mach.h>
76 #include <mach/mach_time.h>
77 #endif
78
79 #include <time.h>
80
81 static gint64
82 get_boot_time (void)
83 {
84 #if defined (HAVE_SYS_PARAM_H) && defined (KERN_BOOTTIME)
85         int mib [2];
86         size_t size;
87         time_t now;
88         struct timeval boottime;
89
90         (void)time(&now);
91
92         mib [0] = CTL_KERN;
93         mib [1] = KERN_BOOTTIME;
94
95         size = sizeof(boottime);
96
97         if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
98                 return (gint64)((now - boottime.tv_sec) * MTICKS_PER_SEC);
99 #else
100         FILE *uptime = fopen ("/proc/uptime", "r");
101         if (uptime) {
102                 double upt;
103                 if (fscanf (uptime, "%lf", &upt) == 1) {
104                         gint64 now = mono_100ns_ticks ();
105                         fclose (uptime);
106                         return now - (gint64)(upt * MTICKS_PER_SEC);
107                 }
108                 fclose (uptime);
109         }
110 #endif
111         /* a made up uptime of 300 seconds */
112         return (gint64)300 * MTICKS_PER_SEC;
113 }
114
115 /* Returns the number of milliseconds from boot time: this should be monotonic */
116 guint32
117 mono_msec_ticks (void)
118 {
119         static gint64 boot_time = 0;
120         gint64 now;
121         if (!boot_time)
122                 boot_time = get_boot_time ();
123         now = mono_100ns_ticks ();
124         /*printf ("now: %llu (boot: %llu) ticks: %llu\n", (gint64)now, (gint64)boot_time, (gint64)(now - boot_time));*/
125         return (now - boot_time)/10000;
126 }
127
128 /* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
129 gint64
130 mono_100ns_ticks (void)
131 {
132         struct timeval tv;
133 #ifdef CLOCK_MONOTONIC
134         struct timespec tspec;
135         static struct timespec tspec_freq = {0};
136         static int can_use_clock = 0;
137         if (!tspec_freq.tv_nsec) {
138                 can_use_clock = clock_getres (CLOCK_MONOTONIC, &tspec_freq) == 0;
139                 /*printf ("resolution: %lu.%lu\n", tspec_freq.tv_sec, tspec_freq.tv_nsec);*/
140         }
141         if (can_use_clock) {
142                 if (clock_gettime (CLOCK_MONOTONIC, &tspec) == 0) {
143                         /*printf ("time: %lu.%lu\n", tspec.tv_sec, tspec.tv_nsec); */
144                         return ((gint64)tspec.tv_sec * MTICKS_PER_SEC + tspec.tv_nsec / 100);
145                 }
146         }
147         
148 #elif defined(PLATFORM_MACOSX)
149         /* http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
150         static mach_timebase_info_data_t timebase;
151         guint64 now = mach_absolute_time ();
152         if (timebase.denom == 0) {
153                 mach_timebase_info (&timebase);
154                 timebase.denom *= 100; /* we return 100ns ticks */
155         }
156         return now * timebase.numer / timebase.denom;
157 #endif
158         if (gettimeofday (&tv, NULL) == 0)
159                 return ((gint64)tv.tv_sec * 1000000 + tv.tv_usec) * 10;
160         return 0;
161 }
162
163 /*
164  * Magic number to convert unix epoch start to windows epoch start
165  * Jan 1, 1970 into a value which is relative to Jan 1, 1601.
166  */
167 #define EPOCH_ADJUST    ((guint64)11644473600LL)
168
169 /* Returns the number of 100ns ticks since 1/1/1601, UTC timezone */
170 gint64
171 mono_100ns_datetime (void)
172 {
173         struct timeval tv;
174         if (gettimeofday (&tv, NULL) == 0)
175                 return mono_100ns_datetime_from_timeval (tv);
176         return 0;
177 }
178
179 gint64
180 mono_100ns_datetime_from_timeval (struct timeval tv)
181 {
182         return (((gint64)tv.tv_sec + EPOCH_ADJUST) * 1000000 + tv.tv_usec) * 10;
183 }
184
185 #endif
186