+ double jtime;
+ GET_THREAD_PROF (prof);
+ MONO_TIMER_STOP (prof->jit_timer);
+ jtime = MONO_TIMER_ELAPSED (prof->jit_timer);
+ prof->jit_time += jtime;
+ if (jtime > prof->max_jit_time) {
+ prof->max_jit_time = jtime;
+ prof->max_jit_method = method;
+ }
+}
+
+/* about 10 minutes of samples */
+#define MAX_PROF_SAMPLES (1000*60*10)
+static int prof_counts = 0;
+static int prof_ucounts = 0;
+static gpointer* prof_addresses = NULL;
+static GHashTable *prof_table = NULL;
+
+static void
+simple_stat_hit (MonoProfiler *prof, guchar *ip, void *context)
+{
+ int pos;
+
+ if (prof_counts >= MAX_PROF_SAMPLES)
+ return;
+ pos = InterlockedIncrement (&prof_counts);
+ prof_addresses [pos - 1] = ip;
+}
+
+static int
+compare_methods_prof (gconstpointer a, gconstpointer b)
+{
+ int ca = GPOINTER_TO_UINT (g_hash_table_lookup (prof_table, a));
+ int cb = GPOINTER_TO_UINT (g_hash_table_lookup (prof_table, b));
+ return cb-ca;
+}
+
+static void
+prof_foreach (char *method, gpointer c, gpointer data)
+{
+ GList **list = data;
+ *list = g_list_insert_sorted (*list, method, compare_methods_prof);
+}
+
+typedef struct Addr2LineData Addr2LineData;
+
+struct Addr2LineData {
+ Addr2LineData *next;
+ FILE *pipein;
+ FILE *pipeout;
+ char *binary;
+ int child_pid;
+};
+
+static Addr2LineData *addr2line_pipes = NULL;
+
+static char*
+try_addr2line (const char* binary, gpointer ip)
+{
+ char buf [1024];
+ char *res;
+ Addr2LineData *addr2line;
+
+ for (addr2line = addr2line_pipes; addr2line; addr2line = addr2line->next) {
+ if (strcmp (binary, addr2line->binary) == 0)
+ break;
+ }
+ if (!addr2line) {
+ const char *addr_argv[] = {"addr2line", "-f", "-e", binary, NULL};
+ int child_pid;
+ int ch_in, ch_out;
+ if (!g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
+ &child_pid, &ch_in, &ch_out, NULL, NULL)) {
+ return g_strdup (binary);
+ }
+ addr2line = g_new0 (Addr2LineData, 1);
+ addr2line->child_pid = child_pid;
+ addr2line->binary = g_strdup (binary);
+ addr2line->pipein = fdopen (ch_in, "w");
+ addr2line->pipeout = fdopen (ch_out, "r");
+ addr2line->next = addr2line_pipes;
+ addr2line_pipes = addr2line;
+ }
+ fprintf (addr2line->pipein, "%p\n", ip);
+ fflush (addr2line->pipein);
+ /* we first get the func name and then file:lineno in a second line */
+ if (fgets (buf, sizeof (buf), addr2line->pipeout) && buf [0] != '?') {
+ char *end = strchr (buf, '\n');
+ if (end)
+ *end = 0;
+ res = g_strdup_printf ("%s(%s", binary, buf);
+ /* discard the filename/line info */
+ fgets (buf, sizeof (buf), addr2line->pipeout);
+ } else {
+ res = g_strdup (binary);
+ }
+ return res;
+}
+
+static void
+stat_prof_report (void)
+{
+ MonoJitInfo *ji;
+ int count = prof_counts;
+ int i, c;
+ char *mn;
+ gpointer ip;
+ GList *tmp, *sorted = NULL;
+ int pcount = ++ prof_counts;
+
+ prof_counts = MAX_PROF_SAMPLES;
+ for (i = 0; i < count; ++i) {
+ ip = prof_addresses [i];
+ ji = mono_jit_info_table_find (mono_domain_get (), ip);
+ if (ji) {
+ mn = mono_method_full_name (ji->method, TRUE);
+ } else {
+#ifdef HAVE_BACKTRACE_SYMBOLS
+ char **names;
+ char *send;
+ int no_func;
+ prof_ucounts++;
+ names = backtrace_symbols (&ip, 1);
+ send = strchr (names [0], '+');
+ if (send) {
+ *send = 0;
+ no_func = 0;
+ } else {
+ no_func = 1;
+ }
+ send = strchr (names [0], '[');
+ if (send)
+ *send = 0;
+ if (no_func && names [0][0]) {
+ char *endp = strchr (names [0], 0);
+ while (--endp >= names [0] && g_ascii_isspace (*endp))
+ *endp = 0;
+ mn = try_addr2line (names [0], ip);
+ } else {
+ mn = g_strdup (names [0]);
+ }
+ free (names);
+#else
+ prof_ucounts++;
+ mn = g_strdup_printf ("unmanaged [%p]", ip);
+#endif
+ }
+ c = GPOINTER_TO_UINT (g_hash_table_lookup (prof_table, mn));
+ c++;
+ g_hash_table_insert (prof_table, mn, GUINT_TO_POINTER (c));
+ if (c > 1)
+ g_free (mn);
+ }
+ fprintf (poutput, "prof counts: total/unmanaged: %d/%d\n", pcount, prof_ucounts);
+ g_hash_table_foreach (prof_table, (GHFunc)prof_foreach, &sorted);
+ for (tmp = sorted; tmp; tmp = tmp->next) {
+ double perc;
+ c = GPOINTER_TO_UINT (g_hash_table_lookup (prof_table, tmp->data));
+ perc = c*100.0/count;
+ fprintf (poutput, "%7d\t%5.2f %% %s\n", c, perc, (char*)tmp->data);
+ }
+ g_list_free (sorted);
+}
+
+static void
+simple_appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
+{
+ /* FIXME: we should actually record partial data for each domain,
+ * since the ip->ji->method mappings are going away at domain unload time.
+ */
+ if (domain == mono_get_root_domain ())
+ stat_prof_report ();