#include "mono/metadata/profiler-private.h"
#include "mono/metadata/debug-helpers.h"
+#include <string.h>
static MonoProfiler * current_profiler = NULL;
* and improve it to do graphs and more accurate timestamping with rdtsc.
*/
+#define USE_X86TSC 0
+#define USE_WIN32COUNTER 0
+#if USE_X86TSC
+
+typedef struct {
+ unsigned int lows, highs, lowe, highe;
+} MonoRdtscTimer;
+
+#define rdtsc(low,high) \
+ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+static int freq;
+
+static double
+rdtsc_elapsed (MonoRdtscTimer *t)
+{
+ unsigned long long diff;
+ unsigned int highe = t->highe;
+ if (t->lowe < t->lows)
+ highe--;
+ diff = (((unsigned long long) highe - t->highs) << 32) + (t->lowe - t->lows);
+ return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
+}
+
+static int
+have_rdtsc (void) {
+ char buf[256];
+ int have_freq = 0;
+ int have_flag = 0;
+ float val;
+ FILE *cpuinfo;
+
+ if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
+ return 0;
+ while (fgets (buf, sizeof(buf), cpuinfo)) {
+ if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
+ /*printf ("got mh: %f\n", val);*/
+ have_freq = val;
+ }
+ if (strncmp (buf, "flags", 5) == 0) {
+ if (strstr (buf, "tsc")) {
+ have_flag = 1;
+ /*printf ("have tsc\n");*/
+ }
+ }
+ }
+ fclose (cpuinfo);
+ return have_flag? have_freq: 0;
+}
+
+#define MONO_TIMER_STARTUP \
+ if (!(freq = have_rdtsc ())) g_error ("Compiled with TSC support, but none found");
+#define MONO_TIMER_TYPE MonoRdtscTimer
+#define MONO_TIMER_INIT(t)
+#define MONO_TIMER_DESTROY(t)
+#define MONO_TIMER_START(t) rdtsc ((t).lows, (t).highs);
+#define MONO_TIMER_STOP(t) rdtsc ((t).lowe, (t).highe);
+#define MONO_TIMER_ELAPSED(t) rdtsc_elapsed (&(t))
+
+#elif USE_WIN32COUNTER
+#include <windows.h>
+
+typedef struct {
+ LARGE_INTEGER start, stop;
+} MonoWin32Timer;
+
+static int freq;
+
+static double
+win32_elapsed (MonoWin32Timer *t)
+{
+ LONGLONG diff = t->stop.QuadPart - t->start.QuadPart;
+ return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
+}
+
+static int
+have_win32counter (void) {
+ LARGE_INTEGER f;
+
+ if (!QueryPerformanceFrequency (&f))
+ return 0;
+ return f.LowPart;
+}
+
+#define MONO_TIMER_STARTUP \
+ if (!(freq = have_win32counter ())) g_error ("Compiled with Win32 counter support, but none found");
+#define MONO_TIMER_TYPE MonoWin32Timer
+#define MONO_TIMER_INIT(t)
+#define MONO_TIMER_DESTROY(t)
+#define MONO_TIMER_START(t) QueryPerformanceCounter (&(t).start)
+#define MONO_TIMER_STOP(t) QueryPerformanceCounter (&(t).stop)
+#define MONO_TIMER_ELAPSED(t) win32_elapsed (&(t))
+
+#else
+
+typedef struct {
+ GTimeVal start, stop;
+} MonoGLibTimer;
+
+static double
+timeval_elapsed (MonoGLibTimer *t)
+{
+ if (t->start.tv_usec > t->stop.tv_usec) {
+ t->stop.tv_usec += G_USEC_PER_SEC;
+ t->stop.tv_sec--;
+ }
+ return (t->stop.tv_sec - t->start.tv_sec)
+ + ((double)(t->stop.tv_usec - t->start.tv_usec))/ G_USEC_PER_SEC;
+}
+
+#define MONO_TIMER_STARTUP
+#define MONO_TIMER_TYPE MonoGLibTimer
+#define MONO_TIMER_INIT(t)
+#define MONO_TIMER_DESTROY(t)
+#define MONO_TIMER_START(t) g_get_current_time (&(t).start)
+#define MONO_TIMER_STOP(t) g_get_current_time (&(t).stop)
+#define MONO_TIMER_ELAPSED(t) timeval_elapsed (&(t))
+#endif
+
struct _MonoProfiler {
GHashTable *methods;
GHashTable *newobjs;
- GTimer *jit_timer;
+ MONO_TIMER_TYPE jit_timer;
double jit_time;
int methods_jitted;
};
typedef struct {
union {
- GTimer *timer;
+ MONO_TIMER_TYPE timer;
MonoMethod *method;
} u;
guint64 count;
double total;
} MethodProfile;
+typedef struct _MethodCallProfile MethodCallProfile;
+
+struct _MethodCallProfile {
+ MethodCallProfile *next;
+ MONO_TIMER_TYPE timer;
+ MonoMethod *method;
+};
+
static gint
compare_profile (MethodProfile *profa, MethodProfile *profb)
{
static void
build_profile (MonoMethod *m, MethodProfile *prof, GList **funcs)
{
- g_timer_destroy (prof->u.timer);
+ MONO_TIMER_DESTROY (prof->u.timer);
prof->u.method = m;
*funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_profile);
}
MethodProfile *p;
char buf [256];
char *sig;
+ guint64 total_calls = 0;
if (funcs)
g_print ("Method name\t\t\t\t\tTotal (ms) Calls Per call (ms)\n");
for (tmp = funcs; tmp; tmp = tmp->next) {
p = tmp->data;
+ total_calls += p->count;
if (!(gint)(p->total*1000))
continue;
sig = mono_signature_get_desc (p->u.method->signature, FALSE);
printf ("%-52s %7d %7llu %7d\n", buf,
(gint)(p->total*1000), p->count, (gint)((p->total*1000)/p->count));
}
+ printf ("Total number of calls: %lld\n", total_calls);
}
typedef struct {
for (tmp = proflist; tmp; tmp = tmp->next) {
p = tmp->data;
klass = p->klass;
- if (strcmp (klass->name, "Array") == 0) {
+ if (klass->rank) {
isarray = "[]";
klass = klass->element_class;
} else {
MethodProfile *profile_info;
if (!(profile_info = g_hash_table_lookup (prof->methods, method))) {
profile_info = g_new0 (MethodProfile, 1);
- profile_info->u.timer = g_timer_new ();
+ MONO_TIMER_INIT (profile_info->u.timer);
g_hash_table_insert (prof->methods, method, profile_info);
}
profile_info->count++;
- g_timer_start (profile_info->u.timer);
+ MONO_TIMER_START (profile_info->u.timer);
}
static void
if (!(profile_info = g_hash_table_lookup (prof->methods, method)))
g_assert_not_reached ();
- g_timer_stop (profile_info->u.timer);
- profile_info->total += g_timer_elapsed (profile_info->u.timer, NULL);
+ MONO_TIMER_STOP (profile_info->u.timer);
+ profile_info->total += MONO_TIMER_ELAPSED (profile_info->u.timer);
}
static void
simple_method_jit (MonoProfiler *prof, MonoMethod *method)
{
- g_timer_start (prof->jit_timer);
prof->methods_jitted++;
+ MONO_TIMER_START (prof->jit_timer);
}
static void
simple_method_end_jit (MonoProfiler *prof, MonoMethod *method, int result)
{
- g_timer_stop (prof->jit_timer);
- prof->jit_time += g_timer_elapsed (prof->jit_timer, NULL);
+ MONO_TIMER_STOP (prof->jit_timer);
+ prof->jit_time += MONO_TIMER_ELAPSED (prof->jit_timer);
}
static void
{
MonoProfiler *prof = g_new0 (MonoProfiler, 1);
+ MONO_TIMER_STARTUP;
+
prof->methods = g_hash_table_new (g_direct_hash, g_direct_equal);
prof->newobjs = g_hash_table_new (g_direct_hash, g_direct_equal);
- prof->jit_timer = g_timer_new ();
+ MONO_TIMER_INIT (prof->jit_timer);
mono_profiler_install (prof, simple_shutdown);
/* later do also object creation */