Merge pull request #3613 from kloun/patch-4
[mono-project.git] / mono / profiler / utils.c
blobcfa7589a6b2bd0edaf550bea60c8250e680bc536
1 /*
2 * utils.c: log profiler and reporter utils
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).
11 * Author:
12 * Paolo Molaro (lupus@ximian.com)
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.
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 #include <glib.h>
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
38 #if defined(__APPLE__)
39 #include <mach/mach_time.h>
40 #include <stdio.h>
42 static mach_timebase_info_data_t timebase_info;
43 #endif
45 #ifndef MAP_ANONYMOUS
46 #define MAP_ANONYMOUS MAP_ANON
47 #endif
49 #define TICKS_PER_SEC 1000000000LL
51 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU)
52 #define HAVE_RDTSC 1
53 #endif
55 typedef struct {
56 unsigned int timer_count;
57 int last_cpu;
58 uint64_t last_rdtsc;
59 uint64_t last_time;
60 } TlsData;
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 *) g_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 *) g_calloc (sizeof (TlsData), 1); pthread_setspecific (tls_data, tls); }
73 #define TLS_INIT(x) pthread_key_create(&x, NULL)
74 #endif
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
83 static int timer_overhead = 0;
84 static uint64_t time_inc = 0;
85 typedef uint64_t (*TimeFunc)(void);
87 static TimeFunc time_func;
89 static uint64_t
90 clock_time (void)
92 #if defined(__APPLE__)
93 uint64_t time = mach_absolute_time ();
95 time *= timebase_info.numer;
96 time /= timebase_info.denom;
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
114 /* must be power of two */
115 #define TIME_ADJ 8
117 static uint64_t
118 fast_current_time (void)
120 DECL_TLS_DATA;
121 if (tls->timer_count++ & (TIME_ADJ - 1)) {
122 tls->last_time += time_inc;
123 return tls->last_time;
125 tls->last_time = clock_time ();
126 return tls->last_time;
129 #if HAVE_RDTSC
131 #define rdtsc(low,high) \
132 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
134 static uint64_t
135 safe_rdtsc (int *cpu)
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;
146 *cpu = c1;
147 return (((uint64_t) high) << 32) + (uint64_t)low;
150 static double cpu_freq;
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 ();
161 if (cpu < 0)
162 return 0;
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;
172 if (strncmp (buf, "flags :", 5) == 0) {
173 if (strstr (buf, "constant_tsc")) {
174 have_flag = 1;
175 /*printf ("have tsc\n");*/
179 fclose (cpuinfo);
180 return have_flag? have_freq: 0;
183 static uint64_t
184 rdtsc_current_time (void)
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");
200 } else {
201 //printf ("wrong cpu: %d\n", cpu);
204 tls->last_time = clock_time ();
205 tls->last_rdtsc = safe_rdtsc (&tls->last_cpu);
206 return tls->last_time;
208 #else
209 #define have_rdtsc() 0
210 #define rdtsc_current_time fast_current_time
211 #endif
213 static uint64_t
214 null_time (void)
216 static uint64_t timer = 0;
217 return timer++;
220 void
221 utils_init (int fast_time)
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
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;
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;
259 get_timer_overhead (void)
261 return timer_overhead;
264 uint64_t
265 current_time (void)
267 return time_func ();
270 void*
271 alloc_buffer (int size)
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
285 void
286 free_buffer (void *buf, int size)
288 #ifdef HOST_WIN32
289 VirtualFree (buf, 0, MEM_RELEASE);
290 #else
291 munmap (buf, size);
292 #endif
295 void
296 take_lock (void)
298 #ifdef HOST_WIN32
299 EnterCriticalSection (&log_lock);
300 #else
301 pthread_mutex_lock (&log_lock);
302 #endif
305 void
306 release_lock (void)
308 #ifdef HOST_WIN32
309 LeaveCriticalSection (&log_lock);
310 #else
311 pthread_mutex_unlock (&log_lock);
312 #endif
315 void
316 encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
318 uint8_t *p = buf;
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);
328 *endbuf = p;
331 void
332 encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
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;
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
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;
359 *endbuf = p;
362 uint64_t
363 decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
365 uint64_t res = 0;
366 int shift = 0;
368 while (1) {
369 uint8_t b = *buf++;
371 res |= (((uint64_t)(b & 0x7f)) << shift);
372 if (!(b & 0x80))
373 break;
374 shift += 7;
377 *endbuf = buf;
379 return res;
382 intptr_t
383 decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
385 uint8_t *p = buf;
386 intptr_t res = 0;
387 int shift = 0;
389 while (1) {
390 uint8_t b = *p;
391 p ++;
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;
402 *endbuf = p;
404 return res;
407 uintptr_t
408 thread_id (void)
410 #ifdef HOST_WIN32
411 return (uintptr_t)GetCurrentThreadId ();
412 #else
413 return (uintptr_t)pthread_self ();
414 #endif
417 uintptr_t
418 process_id (void)
420 #ifdef HOST_WIN32
421 return GetCurrentProcessId ();
422 #else
423 return (uintptr_t)getpid ();
424 #endif