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)
30 #ifdef HAVE_SYS_TIME_H
37 #if defined(__APPLE__)
38 #include <mach/mach_time.h>
41 static mach_timebase_info_data_t timebase_info
;
45 #define MAP_ANONYMOUS MAP_ANON
48 #define TICKS_PER_SEC 1000000000LL
50 #if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU)
55 unsigned int timer_count
;
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()
66 static __thread TlsData tls_data
;
67 #define DECL_TLS_DATA TlsData *tls = &tls_data
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)
76 static CRITICAL_SECTION log_lock
;
77 static LARGE_INTEGER pcounter_freq
;
79 static pthread_mutex_t log_lock
= PTHREAD_MUTEX_INITIALIZER
;
82 static int timer_overhead
= 0;
83 static uint64_t time_inc
= 0;
84 typedef uint64_t (*TimeFunc
)(void);
86 static TimeFunc time_func
;
91 #if defined(__APPLE__)
92 uint64_t time
= mach_absolute_time ();
94 time
*= timebase_info
.numer
;
95 time
/= timebase_info
.denom
;
98 #elif defined(HOST_WIN32)
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
);
108 gettimeofday (&tv
, NULL
);
109 return ((uint64_t)tv
.tv_sec
* TICKS_PER_SEC
+ tv
.tv_usec
* 1000);
113 /* must be power of two */
117 fast_current_time (void)
120 if (tls
->timer_count
++ & (TIME_ADJ
- 1)) {
121 tls
->last_time
+= time_inc
;
122 return tls
->last_time
;
124 tls
->last_time
= clock_time ();
125 return tls
->last_time
;
130 #define rdtsc(low,high) \
131 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
134 safe_rdtsc (int *cpu
)
136 unsigned int low
, high
;
137 int c1
= sched_getcpu ();
140 c2
= sched_getcpu ();
146 return (((uint64_t) high
) << 32) + (uint64_t)low
;
149 static double cpu_freq
;
158 int cpu
= sched_getcpu ();
163 if (!(cpuinfo
= fopen ("/proc/cpuinfo", "r")))
165 while (fgets (buf
, sizeof(buf
), cpuinfo
)) {
166 if (sscanf (buf
, "cpu MHz : %f", &val
) == 1) {
167 /*printf ("got mh: %f\n", val);*/
169 cpu_freq
= val
* 1000000;
171 if (strncmp (buf
, "flags :", 5) == 0) {
172 if (strstr (buf
, "constant_tsc")) {
174 /*printf ("have tsc\n");*/
179 return have_flag
? have_freq
: 0;
183 rdtsc_current_time (void)
186 if (tls
->timer_count
++ & (TIME_ADJ
*8 - 1)) {
188 uint64_t tsc
= safe_rdtsc (&cpu
);
189 if (cpu
!= -1 && cpu
== tls
->last_cpu
) {
190 int64_t diff
= tsc
- tls
->last_rdtsc
;
193 nsecs
= (double)diff
/cpu_freq
;
194 //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
195 return tls
->last_time
+ nsecs
;
197 printf ("tsc went backwards\n");
200 //printf ("wrong cpu: %d\n", cpu);
203 tls
->last_time
= clock_time ();
204 tls
->last_rdtsc
= safe_rdtsc (&tls
->last_cpu
);
205 return tls
->last_time
;
208 #define have_rdtsc() 0
209 #define rdtsc_current_time fast_current_time
215 static uint64_t timer
= 0;
220 utils_init (int fast_time
)
223 uint64_t time_start
, time_end
;
226 InitializeCriticalSection (&log_lock
);
227 QueryPerformanceFrequency (&pcounter_freq
);
229 #if defined (__APPLE__)
230 mach_timebase_info (&timebase_info
);
234 time_func
= null_time
;
235 } else if (fast_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);*/
244 time_func
= rdtsc_current_time
;
246 time_func
= fast_current_time
;
248 time_func
= clock_time
;
250 time_start
= time_func ();
251 for (i
= 0; i
< 256; ++i
)
253 time_end
= time_func ();
254 timer_overhead
= (time_end
- time_start
) / 256;
258 get_timer_overhead (void)
260 return timer_overhead
;
270 alloc_buffer (int size
)
274 ptr
= VirtualAlloc (NULL
, size
, MEM_COMMIT
, PAGE_READWRITE
);
277 ptr
= mmap (NULL
, size
, PROT_READ
|PROT_WRITE
, MAP_ANONYMOUS
|MAP_PRIVATE
, -1, 0);
278 if (ptr
== (void*)-1)
285 free_buffer (void *buf
, int size
)
288 VirtualFree (buf
, 0, MEM_RELEASE
);
298 EnterCriticalSection (&log_lock
);
300 pthread_mutex_lock (&log_lock
);
308 LeaveCriticalSection (&log_lock
);
310 pthread_mutex_unlock (&log_lock
);
315 encode_uleb128 (uint64_t value
, uint8_t *buf
, uint8_t **endbuf
)
320 uint8_t b
= value
& 0x7f;
322 if (value
!= 0) /* more bytes to come */
331 encode_sleb128 (intptr_t value
, uint8_t *buf
, uint8_t **endbuf
)
334 int negative
= (value
< 0);
335 unsigned int size
= sizeof (intptr_t) * 8;
342 /* the following is unnecessary if the
343 * implementation of >>= uses an arithmetic rather
344 * than logical shift for a signed left operand
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)))
362 decode_uleb128 (uint8_t *buf
, uint8_t **endbuf
)
370 res
|= (((uint64_t)(b
& 0x7f)) << shift
);
382 decode_sleb128 (uint8_t *buf
, uint8_t **endbuf
)
392 res
= res
| (((intptr_t)(b
& 0x7f)) << shift
);
395 if (shift
< sizeof (intptr_t) * 8 && (b
& 0x40))
396 res
|= - ((intptr_t)1 << shift
);
410 return (uintptr_t)GetCurrentThreadId ();
412 return (uintptr_t)pthread_self ();
420 return 0; /* FIXME */
422 return (uintptr_t)getpid ();