Ported log profiler to windows (untested) and OSX time factor fix.
[mono.git] / mono / profiler / utils.c
1 #include <stdlib.h>
2 #include <inttypes.h>
3 #include <time.h>
4 #include <stdio.h>
5 #include <string.h>
6 #ifdef HOST_WIN32
7 #include <windows.h>
8 #else
9 #include <pthread.h>
10 #include <sched.h>
11 #endif
12
13 #include "utils.h"
14
15 //#ifdef HAVE_SYS_TIME_H
16 #include <sys/time.h>
17 //#endif
18 //#if HAVE_SYS_MMAN_H
19 #include <sys/mman.h>
20 //#endif
21
22 #if defined(__APPLE__)
23 #include <mach/mach_time.h>  
24 #include <stdio.h> 
25
26 static mach_timebase_info_data_t timebase_info;
27 #endif
28
29 #ifndef MAP_ANON
30 #define MAP_ANONYMOUS MAP_ANON
31 #endif
32
33 #define TICKS_PER_SEC 1000000000LL
34
35 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__)
36 #define HAVE_RDTSC 1
37 #endif
38
39 typedef struct {
40         unsigned int timer_count;
41         int last_cpu;
42         uint64_t last_rdtsc;
43         uint64_t last_time;
44 } TlsData;
45
46 #ifdef HOST_WIN32
47 static int tls_data;
48 #define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) TlsGetValue (tls_data); if (tls == NULL) { tls = (TlsData *) calloc (sizeof (TlsData), 1); TlsSetValue (tls_data, tls); }
49 #define TLS_INIT(x) x = TlsAlloc()
50 #elif HAVE_KW_THREAD
51 static __thread TlsData tls_data;
52 #define DECL_TLS_DATA TlsData *tls = &tls_data
53 #define TLS_INIT(x)
54 #else
55 static pthread_key_t tls_data;
56 #define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) pthread_getspecific (tls_data); if (tls == NULL) { tls = (TlsData *) calloc (sizeof (TlsData), 1); pthread_setspecific (tls_data, tls); }
57 #define TLS_INIT(x) pthread_key_create(&x, NULL)
58 #endif
59
60 #ifdef HOST_WIN32
61 static CRITICAL_SECTION log_lock;
62 #else
63 static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
64 #endif
65
66 static uint64_t time_inc = 0;
67 typedef uint64_t (*TimeFunc)(void);
68
69 static TimeFunc time_func;
70
71 static uint64_t
72 clock_time (void)
73 {
74 #if defined(__APPLE__)
75         uint64_t time = mach_absolute_time ();
76         
77         time *= info.numer;
78         time /= info.denom;
79
80         return time;
81 #else
82         struct timespec tspec;
83         clock_gettime (CLOCK_MONOTONIC, &tspec);
84         return ((uint64_t)tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
85 #endif
86 }
87
88 /* must be power of two */
89 #define TIME_ADJ 8
90
91 static uint64_t
92 fast_current_time (void)
93 {
94         DECL_TLS_DATA;
95         if (tls->timer_count++ & (TIME_ADJ - 1)) {
96                 tls->last_time += time_inc;
97                 return tls->last_time;
98         }
99         tls->last_time = clock_time ();
100         return tls->last_time;
101 }
102
103 #if HAVE_RDTSC
104
105 #define rdtsc(low,high) \
106         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
107
108 static uint64_t
109 safe_rdtsc (int *cpu)
110 {
111         unsigned int low, high;
112         int c1 = sched_getcpu ();
113         int c2;
114         rdtsc (low, high);
115         c2 = sched_getcpu ();
116         if (c1 != c2) {
117                 *cpu = -1;
118                 return 0;
119         }
120         *cpu = c1;
121         return (((uint64_t) high) << 32) + (uint64_t)low;
122 }
123
124 static double cpu_freq;
125
126 static int 
127 have_rdtsc (void) {
128         char buf[256];
129         int have_freq = 0;
130         int have_flag = 0;
131         float val;
132         FILE *cpuinfo;
133         int cpu = sched_getcpu ();
134
135         if (cpu < 0)
136                 return 0;
137
138         if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
139                 return 0;
140         while (fgets (buf, sizeof(buf), cpuinfo)) {
141                 if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
142                         /*printf ("got mh: %f\n", val);*/
143                         have_freq = 1;
144                         cpu_freq = val * 1000000;
145                 }
146                 if (strncmp (buf, "flags :", 5) == 0) {
147                         if (strstr (buf, "constant_tsc")) {
148                                 have_flag = 1;
149                                 /*printf ("have tsc\n");*/
150                         }
151                 }
152         }
153         fclose (cpuinfo);
154         return have_flag? have_freq: 0;
155 }
156
157 static uint64_t
158 rdtsc_current_time (void)
159 {
160         DECL_TLS_DATA;
161         if (tls->timer_count++ & (TIME_ADJ*8 - 1)) {
162                 int cpu;
163                 uint64_t tsc = safe_rdtsc (&cpu);
164                 if (cpu != -1 && cpu == tls->last_cpu) {
165                         int64_t diff = tsc - tls->last_rdtsc;
166                         uint64_t nsecs;
167                         if (diff > 0) {
168                                 nsecs = (double)diff/cpu_freq;
169                                 //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
170                                 return tls->last_time + nsecs;
171                         } else {
172                                 printf ("tsc went backwards\n");
173                         }
174                 } else {
175                         //printf ("wrong cpu: %d\n", cpu);
176                 }
177         }
178         tls->last_time = clock_time ();
179         tls->last_rdtsc = safe_rdtsc (&tls->last_cpu);
180         return tls->last_time;
181 }
182 #else
183 #define have_rdtsc() 0
184 #define rdtsc_current_time fast_current_time
185 #endif
186
187 static uint64_t
188 null_time (void)
189 {
190         static uint64_t timer = 0;
191         return timer++;
192 }
193
194 void
195 utils_init (int fast_time)
196 {
197         TLS_INIT (tls_data);
198 #ifdef HOST_WIN32
199         InitializeCriticalSection (&log_lock);
200 #endif
201 #if defined (__APPLE__)
202         mach_timebase_info (&timebase_info);
203 #endif
204
205         if (fast_time > 1) {
206                 time_func = null_time;
207         } else if (fast_time) {
208                 uint64_t timea;
209                 uint64_t timeb;
210                 clock_time ();
211                 timea = clock_time ();
212                 timeb = clock_time ();
213                 time_inc = (timeb - timea) / TIME_ADJ;
214                 /*printf ("time inc: %llu, timea: %llu, timeb: %llu, diff: %llu\n", time_inc, timea, timeb, timec-timeb);*/
215                 if (have_rdtsc ())
216                         time_func = rdtsc_current_time;
217                 else
218                         time_func = fast_current_time;
219         } else {
220                 time_func = clock_time;
221         }
222 }
223
224 uint64_t
225 current_time (void)
226 {
227         return time_func ();
228 }
229
230 void*
231 alloc_buffer (int size)
232 {
233         void *ptr;
234 #ifdef HOST_WIN32
235         ptr = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);
236         return ptr;
237 #else
238         ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
239         if (ptr == (void*)-1)
240                 return NULL;
241         return ptr;
242 #endif
243 }
244
245 void
246 free_buffer (void *buf, int size)
247 {
248 #ifdef HOST_WIN32
249         VirtualFree (buf, 0, MEM_RELEASE);
250 #else
251         munmap (buf, size);
252 #endif
253 }
254
255 void
256 take_lock (void)
257 {
258 #ifdef HOST_WIN32
259         EnterCriticalSection (&log_lock);
260 #else
261         pthread_mutex_lock (&log_lock);
262 #endif
263 }
264
265 void
266 release_lock (void)
267 {
268 #ifdef HOST_WIN32
269         LeaveCriticalSection (&log_lock);
270 #else
271         pthread_mutex_unlock (&log_lock);
272 #endif
273 }
274
275 void
276 encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
277 {
278         uint8_t *p = buf;
279
280         do {
281                 uint8_t b = value & 0x7f;
282                 value >>= 7;
283                 if (value != 0) /* more bytes to come */
284                         b |= 0x80;
285                 *p ++ = b;
286         } while (value);
287
288         *endbuf = p;
289 }
290
291 void
292 encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
293 {
294         int more = 1;
295         int negative = (value < 0);
296         unsigned int size = sizeof (intptr_t) * 8;
297         uint8_t byte;
298         uint8_t *p = buf;
299
300         while (more) {
301                 byte = value & 0x7f;
302                 value >>= 7;
303                 /* the following is unnecessary if the
304                  * implementation of >>= uses an arithmetic rather
305                  * than logical shift for a signed left operand
306                  */
307                 if (negative)
308                         /* sign extend */
309                         value |= - ((intptr_t)1 <<(size - 7));
310                 /* sign bit of byte is second high order bit (0x40) */
311                 if ((value == 0 && !(byte & 0x40)) ||
312                         (value == -1 && (byte & 0x40)))
313                         more = 0;
314                 else
315                         byte |= 0x80;
316                 *p ++= byte;
317         }
318
319         *endbuf = p;
320 }
321
322 uint64_t
323 decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
324 {
325         uint64_t res = 0;
326         int shift = 0;
327
328         while (1) {
329                 uint8_t b = *buf++;
330
331                 res |= (((uint64_t)(b & 0x7f)) << shift);
332                 if (!(b & 0x80))
333                         break;
334                 shift += 7;
335         }
336
337         *endbuf = buf;
338
339         return res;
340 }
341
342 intptr_t
343 decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
344 {
345         uint8_t *p = buf;
346         intptr_t res = 0;
347         int shift = 0;
348
349         while (1) {
350                 uint8_t b = *p;
351                 p ++;
352
353                 res = res | (((intptr_t)(b & 0x7f)) << shift);
354                 shift += 7;
355                 if (!(b & 0x80)) {
356                         if (shift < sizeof (intptr_t) * 8 && (b & 0x40))
357                                 res |= - ((intptr_t)1 << shift);
358                         break;
359                 }
360         }
361
362         *endbuf = p;
363
364         return res;
365 }
366
367 uintptr_t
368 thread_id (void)
369 {
370 #ifdef HOST_WIN32
371         return (uintptr_t)GetCurrentThreadId ();
372 #else
373         return (uintptr_t)pthread_self ();
374 #endif
375 }
376