First set of licensing changes
[mono.git] / mono / profiler / utils.c
1 /*
2  * utils.c: log profiler and reporter utils
3  *
4  * We have here the minimal needed portability functions: we can't depend
5  * on the ones provided by the runtime, since they are internal and,
6  * especially mprof-report is an external program.
7  * Note also that we don't take a glib/eglib dependency here for mostly
8  * the same reason (but also because we need tight control in the profiler
9  * over memory allocation, which needs to work with the world stopped).
10  *
11  * Author:
12  *   Paolo Molaro (lupus@ximian.com)
13  *
14  * Copyright 2010 Novell, Inc (http://www.novell.com)
15  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16  */
17 #include "utils.h"
18 #include <stdlib.h>
19 #include <time.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #ifdef HOST_WIN32
24 #include <windows.h>
25 #else
26 #include <pthread.h>
27 #include <sched.h>
28 #endif
29
30
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34 #if HAVE_SYS_MMAN_H
35 #include <sys/mman.h>
36 #endif
37
38 #if defined(__APPLE__)
39 #include <mach/mach_time.h>  
40 #include <stdio.h> 
41
42 static mach_timebase_info_data_t timebase_info;
43 #endif
44
45 #ifndef MAP_ANONYMOUS
46 #define MAP_ANONYMOUS MAP_ANON
47 #endif
48
49 #define TICKS_PER_SEC 1000000000LL
50
51 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU)
52 #define HAVE_RDTSC 1
53 #endif
54
55 typedef struct {
56         unsigned int timer_count;
57         int last_cpu;
58         uint64_t last_rdtsc;
59         uint64_t last_time;
60 } TlsData;
61
62 #ifdef HOST_WIN32
63 static int tls_data;
64 #define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) TlsGetValue (tls_data); if (tls == NULL) { tls = (TlsData *) calloc (sizeof (TlsData), 1); TlsSetValue (tls_data, tls); }
65 #define TLS_INIT(x) x = TlsAlloc()
66 #elif HAVE_KW_THREAD
67 static __thread TlsData tls_data;
68 #define DECL_TLS_DATA TlsData *tls = &tls_data
69 #define TLS_INIT(x)
70 #else
71 static pthread_key_t tls_data;
72 #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); }
73 #define TLS_INIT(x) pthread_key_create(&x, NULL)
74 #endif
75
76 #ifdef HOST_WIN32
77 static CRITICAL_SECTION log_lock;
78 static LARGE_INTEGER pcounter_freq;
79 #else
80 static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
81 #endif
82
83 static int timer_overhead = 0;
84 static uint64_t time_inc = 0;
85 typedef uint64_t (*TimeFunc)(void);
86
87 static TimeFunc time_func;
88
89 static uint64_t
90 clock_time (void)
91 {
92 #if defined(__APPLE__)
93         uint64_t time = mach_absolute_time ();
94         
95         time *= timebase_info.numer;
96         time /= timebase_info.denom;
97
98         return time;
99 #elif defined(HOST_WIN32)
100         LARGE_INTEGER value;
101         QueryPerformanceCounter (&value);
102         return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart;
103 #elif defined(CLOCK_MONOTONIC)
104         struct timespec tspec;
105         clock_gettime (CLOCK_MONOTONIC, &tspec);
106         return ((uint64_t)tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
107 #else
108         struct timeval tv;
109         gettimeofday (&tv, NULL);
110         return ((uint64_t)tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
111 #endif
112 }
113
114 /* must be power of two */
115 #define TIME_ADJ 8
116
117 static uint64_t
118 fast_current_time (void)
119 {
120         DECL_TLS_DATA;
121         if (tls->timer_count++ & (TIME_ADJ - 1)) {
122                 tls->last_time += time_inc;
123                 return tls->last_time;
124         }
125         tls->last_time = clock_time ();
126         return tls->last_time;
127 }
128
129 #if HAVE_RDTSC
130
131 #define rdtsc(low,high) \
132         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
133
134 static uint64_t
135 safe_rdtsc (int *cpu)
136 {
137         unsigned int low, high;
138         int c1 = sched_getcpu ();
139         int c2;
140         rdtsc (low, high);
141         c2 = sched_getcpu ();
142         if (c1 != c2) {
143                 *cpu = -1;
144                 return 0;
145         }
146         *cpu = c1;
147         return (((uint64_t) high) << 32) + (uint64_t)low;
148 }
149
150 static double cpu_freq;
151
152 static int 
153 have_rdtsc (void) {
154         char buf[256];
155         int have_freq = 0;
156         int have_flag = 0;
157         float val;
158         FILE *cpuinfo;
159         int cpu = sched_getcpu ();
160
161         if (cpu < 0)
162                 return 0;
163
164         if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
165                 return 0;
166         while (fgets (buf, sizeof(buf), cpuinfo)) {
167                 if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
168                         /*printf ("got mh: %f\n", val);*/
169                         have_freq = 1;
170                         cpu_freq = val * 1000000;
171                 }
172                 if (strncmp (buf, "flags :", 5) == 0) {
173                         if (strstr (buf, "constant_tsc")) {
174                                 have_flag = 1;
175                                 /*printf ("have tsc\n");*/
176                         }
177                 }
178         }
179         fclose (cpuinfo);
180         return have_flag? have_freq: 0;
181 }
182
183 static uint64_t
184 rdtsc_current_time (void)
185 {
186         DECL_TLS_DATA;
187         if (tls->timer_count++ & (TIME_ADJ*8 - 1)) {
188                 int cpu;
189                 uint64_t tsc = safe_rdtsc (&cpu);
190                 if (cpu != -1 && cpu == tls->last_cpu) {
191                         int64_t diff = tsc - tls->last_rdtsc;
192                         uint64_t nsecs;
193                         if (diff > 0) {
194                                 nsecs = (double)diff/cpu_freq;
195                                 //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
196                                 return tls->last_time + nsecs;
197                         } else {
198                                 printf ("tsc went backwards\n");
199                         }
200                 } else {
201                         //printf ("wrong cpu: %d\n", cpu);
202                 }
203         }
204         tls->last_time = clock_time ();
205         tls->last_rdtsc = safe_rdtsc (&tls->last_cpu);
206         return tls->last_time;
207 }
208 #else
209 #define have_rdtsc() 0
210 #define rdtsc_current_time fast_current_time
211 #endif
212
213 static uint64_t
214 null_time (void)
215 {
216         static uint64_t timer = 0;
217         return timer++;
218 }
219
220 void
221 utils_init (int fast_time)
222 {
223         int i;
224         uint64_t time_start, time_end;
225         TLS_INIT (tls_data);
226 #ifdef HOST_WIN32
227         InitializeCriticalSection (&log_lock);
228         QueryPerformanceFrequency (&pcounter_freq);
229 #endif
230 #if defined (__APPLE__)
231         mach_timebase_info (&timebase_info);
232 #endif
233
234         if (fast_time > 1) {
235                 time_func = null_time;
236         } else if (fast_time) {
237                 uint64_t timea;
238                 uint64_t timeb;
239                 clock_time ();
240                 timea = clock_time ();
241                 timeb = clock_time ();
242                 time_inc = (timeb - timea) / TIME_ADJ;
243                 /*printf ("time inc: %llu, timea: %llu, timeb: %llu, diff: %llu\n", time_inc, timea, timeb, timec-timeb);*/
244                 if (have_rdtsc ())
245                         time_func = rdtsc_current_time;
246                 else
247                         time_func = fast_current_time;
248         } else {
249                 time_func = clock_time;
250         }
251         time_start = time_func ();
252         for (i = 0; i < 256; ++i)
253                 time_func ();
254         time_end = time_func ();
255         timer_overhead = (time_end - time_start) / 256;
256 }
257
258 int
259 get_timer_overhead (void)
260 {
261         return timer_overhead;
262 }
263
264 uint64_t
265 current_time (void)
266 {
267         return time_func ();
268 }
269
270 void*
271 alloc_buffer (int size)
272 {
273         void *ptr;
274 #ifdef HOST_WIN32
275         ptr = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);
276         return ptr;
277 #else
278         ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
279         if (ptr == MAP_FAILED)
280                 return NULL;
281         return ptr;
282 #endif
283 }
284
285 void
286 free_buffer (void *buf, int size)
287 {
288 #ifdef HOST_WIN32
289         VirtualFree (buf, 0, MEM_RELEASE);
290 #else
291         munmap (buf, size);
292 #endif
293 }
294
295 void
296 take_lock (void)
297 {
298 #ifdef HOST_WIN32
299         EnterCriticalSection (&log_lock);
300 #else
301         pthread_mutex_lock (&log_lock);
302 #endif
303 }
304
305 void
306 release_lock (void)
307 {
308 #ifdef HOST_WIN32
309         LeaveCriticalSection (&log_lock);
310 #else
311         pthread_mutex_unlock (&log_lock);
312 #endif
313 }
314
315 void
316 encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
317 {
318         uint8_t *p = buf;
319
320         do {
321                 uint8_t b = value & 0x7f;
322                 value >>= 7;
323                 if (value != 0) /* more bytes to come */
324                         b |= 0x80;
325                 *p ++ = b;
326         } while (value);
327
328         *endbuf = p;
329 }
330
331 void
332 encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
333 {
334         int more = 1;
335         int negative = (value < 0);
336         unsigned int size = sizeof (intptr_t) * 8;
337         uint8_t byte;
338         uint8_t *p = buf;
339
340         while (more) {
341                 byte = value & 0x7f;
342                 value >>= 7;
343                 /* the following is unnecessary if the
344                  * implementation of >>= uses an arithmetic rather
345                  * than logical shift for a signed left operand
346                  */
347                 if (negative)
348                         /* sign extend */
349                         value |= - ((intptr_t)1 <<(size - 7));
350                 /* sign bit of byte is second high order bit (0x40) */
351                 if ((value == 0 && !(byte & 0x40)) ||
352                         (value == -1 && (byte & 0x40)))
353                         more = 0;
354                 else
355                         byte |= 0x80;
356                 *p ++= byte;
357         }
358
359         *endbuf = p;
360 }
361
362 uint64_t
363 decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
364 {
365         uint64_t res = 0;
366         int shift = 0;
367
368         while (1) {
369                 uint8_t b = *buf++;
370
371                 res |= (((uint64_t)(b & 0x7f)) << shift);
372                 if (!(b & 0x80))
373                         break;
374                 shift += 7;
375         }
376
377         *endbuf = buf;
378
379         return res;
380 }
381
382 intptr_t
383 decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
384 {
385         uint8_t *p = buf;
386         intptr_t res = 0;
387         int shift = 0;
388
389         while (1) {
390                 uint8_t b = *p;
391                 p ++;
392
393                 res = res | (((intptr_t)(b & 0x7f)) << shift);
394                 shift += 7;
395                 if (!(b & 0x80)) {
396                         if (shift < sizeof (intptr_t) * 8 && (b & 0x40))
397                                 res |= - ((intptr_t)1 << shift);
398                         break;
399                 }
400         }
401
402         *endbuf = p;
403
404         return res;
405 }
406
407 uintptr_t
408 thread_id (void)
409 {
410 #ifdef HOST_WIN32
411         return (uintptr_t)GetCurrentThreadId ();
412 #else
413         return (uintptr_t)pthread_self ();
414 #endif
415 }
416
417 uintptr_t
418 process_id (void)
419 {
420 #ifdef HOST_WIN32
421         return 0; /* FIXME */
422 #else
423         return (uintptr_t)getpid ();
424 #endif
425 }
426