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)
15 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
31 #ifdef HAVE_SYS_TIME_H
38 #if defined(__APPLE__)
39 #include <mach/mach_time.h>
42 static mach_timebase_info_data_t timebase_info
;
46 #define MAP_ANONYMOUS MAP_ANON
49 #define TICKS_PER_SEC 1000000000LL
51 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU)
56 unsigned int timer_count
;
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()
67 static __thread TlsData tls_data
;
68 #define DECL_TLS_DATA TlsData *tls = &tls_data
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)
77 static CRITICAL_SECTION log_lock
;
78 static LARGE_INTEGER pcounter_freq
;
80 static pthread_mutex_t log_lock
= PTHREAD_MUTEX_INITIALIZER
;
83 static int timer_overhead
= 0;
84 static uint64_t time_inc
= 0;
85 typedef uint64_t (*TimeFunc
)(void);
87 static TimeFunc time_func
;
92 #if defined(__APPLE__)
93 uint64_t time
= mach_absolute_time ();
95 time
*= timebase_info
.numer
;
96 time
/= timebase_info
.denom
;
99 #elif defined(HOST_WIN32)
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
);
109 gettimeofday (&tv
, NULL
);
110 return ((uint64_t)tv
.tv_sec
* TICKS_PER_SEC
+ tv
.tv_usec
* 1000);
114 /* must be power of two */
118 fast_current_time (void)
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
;
131 #define rdtsc(low,high) \
132 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
135 safe_rdtsc (int *cpu
)
137 unsigned int low
, high
;
138 int c1
= sched_getcpu ();
141 c2
= sched_getcpu ();
147 return (((uint64_t) high
) << 32) + (uint64_t)low
;
150 static double cpu_freq
;
159 int cpu
= sched_getcpu ();
164 if (!(cpuinfo
= fopen ("/proc/cpuinfo", "r")))
166 while (fgets (buf
, sizeof(buf
), cpuinfo
)) {
167 if (sscanf (buf
, "cpu MHz : %f", &val
) == 1) {
168 /*printf ("got mh: %f\n", val);*/
170 cpu_freq
= val
* 1000000;
172 if (strncmp (buf
, "flags :", 5) == 0) {
173 if (strstr (buf
, "constant_tsc")) {
175 /*printf ("have tsc\n");*/
180 return have_flag
? have_freq
: 0;
184 rdtsc_current_time (void)
187 if (tls
->timer_count
++ & (TIME_ADJ
*8 - 1)) {
189 uint64_t tsc
= safe_rdtsc (&cpu
);
190 if (cpu
!= -1 && cpu
== tls
->last_cpu
) {
191 int64_t diff
= tsc
- tls
->last_rdtsc
;
194 nsecs
= (double)diff
/cpu_freq
;
195 //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
196 return tls
->last_time
+ nsecs
;
198 printf ("tsc went backwards\n");
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
;
209 #define have_rdtsc() 0
210 #define rdtsc_current_time fast_current_time
216 static uint64_t timer
= 0;
221 utils_init (int fast_time
)
224 uint64_t time_start
, time_end
;
227 InitializeCriticalSection (&log_lock
);
228 QueryPerformanceFrequency (&pcounter_freq
);
230 #if defined (__APPLE__)
231 mach_timebase_info (&timebase_info
);
235 time_func
= null_time
;
236 } else if (fast_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);*/
245 time_func
= rdtsc_current_time
;
247 time_func
= fast_current_time
;
249 time_func
= clock_time
;
251 time_start
= time_func ();
252 for (i
= 0; i
< 256; ++i
)
254 time_end
= time_func ();
255 timer_overhead
= (time_end
- time_start
) / 256;
259 get_timer_overhead (void)
261 return timer_overhead
;
271 alloc_buffer (int size
)
275 ptr
= VirtualAlloc (NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
278 ptr
= mmap (NULL
, size
, PROT_READ
|PROT_WRITE
, MAP_ANONYMOUS
|MAP_PRIVATE
, -1, 0);
279 if (ptr
== MAP_FAILED
)
286 free_buffer (void *buf
, int size
)
289 VirtualFree (buf
, 0, MEM_RELEASE
);
299 EnterCriticalSection (&log_lock
);
301 pthread_mutex_lock (&log_lock
);
309 LeaveCriticalSection (&log_lock
);
311 pthread_mutex_unlock (&log_lock
);
316 encode_uleb128 (uint64_t value
, uint8_t *buf
, uint8_t **endbuf
)
321 uint8_t b
= value
& 0x7f;
323 if (value
!= 0) /* more bytes to come */
332 encode_sleb128 (intptr_t value
, uint8_t *buf
, uint8_t **endbuf
)
335 int negative
= (value
< 0);
336 unsigned int size
= sizeof (intptr_t) * 8;
343 /* the following is unnecessary if the
344 * implementation of >>= uses an arithmetic rather
345 * than logical shift for a signed left operand
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)))
363 decode_uleb128 (uint8_t *buf
, uint8_t **endbuf
)
371 res
|= (((uint64_t)(b
& 0x7f)) << shift
);
383 decode_sleb128 (uint8_t *buf
, uint8_t **endbuf
)
393 res
= res
| (((intptr_t)(b
& 0x7f)) << shift
);
396 if (shift
< sizeof (intptr_t) * 8 && (b
& 0x40))
397 res
|= - ((intptr_t)1 << shift
);
411 return (uintptr_t)GetCurrentThreadId ();
413 return (uintptr_t)pthread_self ();
421 return GetCurrentProcessId ();
423 return (uintptr_t)getpid ();