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