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).
12 * Paolo Molaro (lupus@ximian.com)
14 * Copyright 2010 Novell, Inc (http://www.novell.com)
29 #ifdef HAVE_SYS_TIME_H
36 #if defined(__APPLE__)
37 #include <mach/mach_time.h>
40 static mach_timebase_info_data_t timebase_info;
44 #define MAP_ANONYMOUS MAP_ANON
47 #define TICKS_PER_SEC 1000000000LL
49 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__)
54 unsigned int timer_count;
62 #define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) TlsGetValue (tls_data); if (tls == NULL) { tls = (TlsData *) calloc (sizeof (TlsData), 1); TlsSetValue (tls_data, tls); }
63 #define TLS_INIT(x) x = TlsAlloc()
65 static __thread TlsData tls_data;
66 #define DECL_TLS_DATA TlsData *tls = &tls_data
69 static pthread_key_t tls_data;
70 #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); }
71 #define TLS_INIT(x) pthread_key_create(&x, NULL)
75 static CRITICAL_SECTION log_lock;
76 static LARGE_INTEGER pcounter_freq;
78 static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
81 static int timer_overhead = 0;
82 static uint64_t time_inc = 0;
83 typedef uint64_t (*TimeFunc)(void);
85 static TimeFunc time_func;
90 #if defined(__APPLE__)
91 uint64_t time = mach_absolute_time ();
93 time *= timebase_info.numer;
94 time /= timebase_info.denom;
97 #elif defined(HOST_WIN32)
99 QueryPerformanceCounter (&value);
100 return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart;
101 #elif defined(CLOCK_MONOTONIC)
102 struct timespec tspec;
103 clock_gettime (CLOCK_MONOTONIC, &tspec);
104 return ((uint64_t)tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
107 gettimeofday (&tv, NULL);
108 return ((uint64_t)tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
112 /* must be power of two */
116 fast_current_time (void)
119 if (tls->timer_count++ & (TIME_ADJ - 1)) {
120 tls->last_time += time_inc;
121 return tls->last_time;
123 tls->last_time = clock_time ();
124 return tls->last_time;
129 #define rdtsc(low,high) \
130 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
133 safe_rdtsc (int *cpu)
135 unsigned int low, high;
136 int c1 = sched_getcpu ();
139 c2 = sched_getcpu ();
145 return (((uint64_t) high) << 32) + (uint64_t)low;
148 static double cpu_freq;
157 int cpu = sched_getcpu ();
162 if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
164 while (fgets (buf, sizeof(buf), cpuinfo)) {
165 if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
166 /*printf ("got mh: %f\n", val);*/
168 cpu_freq = val * 1000000;
170 if (strncmp (buf, "flags :", 5) == 0) {
171 if (strstr (buf, "constant_tsc")) {
173 /*printf ("have tsc\n");*/
178 return have_flag? have_freq: 0;
182 rdtsc_current_time (void)
185 if (tls->timer_count++ & (TIME_ADJ*8 - 1)) {
187 uint64_t tsc = safe_rdtsc (&cpu);
188 if (cpu != -1 && cpu == tls->last_cpu) {
189 int64_t diff = tsc - tls->last_rdtsc;
192 nsecs = (double)diff/cpu_freq;
193 //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
194 return tls->last_time + nsecs;
196 printf ("tsc went backwards\n");
199 //printf ("wrong cpu: %d\n", cpu);
202 tls->last_time = clock_time ();
203 tls->last_rdtsc = safe_rdtsc (&tls->last_cpu);
204 return tls->last_time;
207 #define have_rdtsc() 0
208 #define rdtsc_current_time fast_current_time
214 static uint64_t timer = 0;
219 utils_init (int fast_time)
222 uint64_t time_start, time_end;
225 InitializeCriticalSection (&log_lock);
226 QueryPerformanceFrequency (&pcounter_freq);
228 #if defined (__APPLE__)
229 mach_timebase_info (&timebase_info);
233 time_func = null_time;
234 } else if (fast_time) {
238 timea = clock_time ();
239 timeb = clock_time ();
240 time_inc = (timeb - timea) / TIME_ADJ;
241 /*printf ("time inc: %llu, timea: %llu, timeb: %llu, diff: %llu\n", time_inc, timea, timeb, timec-timeb);*/
243 time_func = rdtsc_current_time;
245 time_func = fast_current_time;
247 time_func = clock_time;
249 time_start = time_func ();
250 for (i = 0; i < 256; ++i)
252 time_end = time_func ();
253 timer_overhead = (time_end - time_start) / 256;
257 get_timer_overhead (void)
259 return timer_overhead;
269 alloc_buffer (int size)
273 ptr = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);
276 ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
277 if (ptr == (void*)-1)
284 free_buffer (void *buf, int size)
287 VirtualFree (buf, 0, MEM_RELEASE);
297 EnterCriticalSection (&log_lock);
299 pthread_mutex_lock (&log_lock);
307 LeaveCriticalSection (&log_lock);
309 pthread_mutex_unlock (&log_lock);
314 encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
319 uint8_t b = value & 0x7f;
321 if (value != 0) /* more bytes to come */
330 encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
333 int negative = (value < 0);
334 unsigned int size = sizeof (intptr_t) * 8;
341 /* the following is unnecessary if the
342 * implementation of >>= uses an arithmetic rather
343 * than logical shift for a signed left operand
347 value |= - ((intptr_t)1 <<(size - 7));
348 /* sign bit of byte is second high order bit (0x40) */
349 if ((value == 0 && !(byte & 0x40)) ||
350 (value == -1 && (byte & 0x40)))
361 decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
369 res |= (((uint64_t)(b & 0x7f)) << shift);
381 decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
391 res = res | (((intptr_t)(b & 0x7f)) << shift);
394 if (shift < sizeof (intptr_t) * 8 && (b & 0x40))
395 res |= - ((intptr_t)1 << shift);
409 return (uintptr_t)GetCurrentThreadId ();
411 return (uintptr_t)pthread_self ();