[Mono-devel-list] XML Profile List

Carlos Alberto Cortez Guevara carlos at unixmexico.org
Tue Mar 23 22:34:39 EST 2004


Hello,

I'm attaching a patch to generate a xml file with the profile data
(intended to be used with the profiler gui). It only add some similar
functions with support for the xml file.

Since this is my first code-patch, I want you to review it.

Regards,
Carlos.

-- 
--------------------------------------------------
/* The definition of myself */
using Cortez;
using GeniusIntelligence;

public class Carlos : Human, IGenius, ILinuxUser {

	static void Main () {
		Me.Think();
	}

}

--------------------------------------------------
-------------- next part --------------
? xml_profile.diff
Index: profiler.c
===================================================================
RCS file: /cvs/public/mono/mono/metadata/profiler.c,v
retrieving revision 1.20
diff -u -r1.20 profiler.c
--- profiler.c	22 Mar 2004 17:48:46 -0000	1.20
+++ profiler.c	24 Mar 2004 02:45:20 -0000
@@ -7,6 +7,8 @@
 #include <gmodule.h>
 
 static MonoProfiler * current_profiler = NULL;
+static const char *profiler_xml_file = NULL;
+static FILE *xml_file = NULL;
 
 static MonoProfileAppDomainFunc   domain_start_load;
 static MonoProfileAppDomainResult domain_end_load;
@@ -682,6 +684,61 @@
 	printf ("Total number of calls: %lld\n", total_calls);
 }
 
+static guint64
+total_number_calls (GList *funcs)
+{
+	GList *tmp;
+	MethodProfile *mp;
+	guint64 total_calls = 0;
+
+	for (tmp = funcs; tmp; tmp = tmp->next) {
+		mp = tmp->data;
+		total_calls += mp->count;
+	}
+
+	return total_calls;
+}
+
+static gboolean output_callers_xml (MethodProfile *p);
+
+static gboolean
+output_profile_xml (GList *funcs)
+{
+	char *m;
+	GList *tmp;
+	guint64 total_calls;
+	int length;
+	MethodProfile *p;
+
+	total_calls = total_number_calls (funcs);
+	length = fprintf (xml_file, "\t<time calls=\"%lld\">\n", total_calls);
+	if (length < 0)
+		return FALSE;
+
+	for (tmp = funcs; tmp; tmp = tmp->next) {
+		p = tmp->data;
+
+		if (!(gint)(p->total*1000))
+			continue;
+
+		m = method_get_name (p->method);
+		length = fprintf (xml_file, "\t\t<method count=\"%llu\" name=\"%s\" time=\"%f\" total=\"%f\">\n",
+				p->count, m, (double) (p->total * 1000)/(double) p->count, (double) p->total * 1000);
+		
+		if (length < 0 || !output_callers_xml (p))
+			return FALSE;
+
+		length = fprintf (xml_file, "\t\t</method>\n");
+		g_free (m);
+
+		if (length < 0)
+			return FALSE;
+	}
+	length = fprintf (xml_file, "\t</time>\n");
+	
+	return (length > 0)?TRUE:FALSE;
+}
+
 typedef struct {
 	MethodProfile *mp;
 	guint count;
@@ -766,6 +823,106 @@
 	}
 }
 
+static gboolean
+output_callers_xml (MethodProfile *p) {
+	char *m;
+	guint total_callers, percent;
+	int length;
+	CallerInfo *cinfo;
+	GSList *sorted, *tmps;
+
+	total_callers = 0;
+	for (cinfo = p->caller_info; cinfo; cinfo = cinfo->next)
+		total_callers += cinfo->count;
+	sorted = sort_caller_list (p->caller_info);
+	for (tmps = sorted; tmps; tmps = tmps->next) {
+		cinfo = tmps->data;
+		percent = (cinfo->count * 100)/total_callers;
+		if (percent < 1)
+			continue;
+		m = method_get_name (cinfo->caller);
+		length = fprintf (xml_file, "\t\t\t<caller count=\"%d\" name=\"%s\" percent=\"%d\"/>\n",
+				cinfo->count, m, percent);
+		g_free (m);
+		if (length < 0)
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static guint
+total_allocated_mem (GList *proflist)
+{
+	GList *tmp;
+	NewobjProfile *p;
+	guint total = 0;
+
+	for (tmp = proflist; tmp; tmp = tmp->next) {
+		p = tmp->data;
+		total += p->count;
+	}
+
+	return total;
+}
+
+static gboolean
+output_newobj_profile_xml (GList *proflist)
+{
+	AllocInfo *ainfo;
+	GList *tmp;
+	GSList *sorted, *tmps;
+	MethodProfile *mp;
+	MonoClass *klass;
+	NewobjProfile *p;
+	const char *isarray;
+	char *m;
+	char buf [256];
+	guint total;
+	int length;
+
+	total = total_allocated_mem (proflist);
+	length = fprintf (xml_file, "\t<allocation mem=\"%d\">\n", total / 1024);
+	if (length < 0)
+		return FALSE;
+	for (tmp = proflist; tmp; tmp = tmp->next) {
+		p = tmp->data;
+		if (p->count < 50000)
+			continue;
+		mp = p->mp;
+		m = method_get_name (mp->method);
+		length = fprintf (xml_file, "\t\t<method size=\"%d\" name=\"%s\">\n", p->count / 1024, m);
+		g_free (m);
+		if (length < 0)
+			return FALSE;
+		sorted = sort_alloc_list (mp->alloc_info);
+		for (tmps = sorted; tmps; tmps = tmps->next) {
+			ainfo = tmps->data;
+			if (ainfo->mem < 50000)
+				continue;
+			klass = ainfo->klass;
+			if (klass->rank) {
+				isarray = "[]";
+				klass = klass->element_class;
+			} else {
+				isarray = "";
+			}
+			g_snprintf (buf, sizeof (buf), "%s.%s%s",
+					klass->name_space, klass->name, isarray);
+			length = fprintf (xml_file, "\t\t\t<alloc count=\"%d\" mem=\"%d\" name=\"%s\" />\n",
+					ainfo->count, ainfo->mem / 1024, buf);
+			if (length < 0)
+				return FALSE;
+		}
+		if (!output_callers_xml (mp) || fprintf (xml_file, "\t\t</method>\n") < 0)
+			return FALSE;
+	}
+
+	length = fprintf (xml_file, "\t</allocation>\n");
+
+	return (length < 0)?FALSE:TRUE;
+}
+
 static void
 output_newobj_profile (GList *proflist)
 {
@@ -1003,13 +1160,87 @@
 }
 
 static void
-simple_shutdown (MonoProfiler *prof)
+profiler_xml_error ()
+{
+	g_error ("Error writing %s.\n", profiler_xml_file);
+}
+
+static void
+simple_shutdown_xml (MonoProfiler *prof)
 {
+	gboolean errors;
+	GList *profile = NULL;
+	GSList *tmp;
+	MonoProfiler *tprof;
+	char *str;
+	int length;
+
+	if (!(xml_file = fopen (profiler_xml_file, "w"))) {
+		g_error ("Unable to create profile data in %s", profiler_xml_file);
+		return;
+	}
+
+	for (tmp = prof->per_thread; tmp; tmp = tmp->next) {
+		tprof = tmp->data;
+		merge_thread_data (prof, tprof);
+	}
+	length = fprintf (xml_file, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<profile methods=\"%d\" total=\"%g\">\n",
+			prof->methods_jitted, prof->jit_time);
+	if (length < 0) {
+		profiler_xml_error ();
+		return;
+	}
+	
+	if (prof->max_jit_method) {
+		str = method_get_name (prof->max_jit_method);
+		length = fprintf (xml_file, "\t<slowest name=\"%s\" time=\"%g\" />\n", str, prof->max_jit_time);
+		g_free (str);
+		if (length < 0) {
+			profiler_xml_error ();
+			return;
+		}
+	}
+	
+	g_hash_table_foreach (prof->methods, (GHFunc)build_profile, &profile);
+	errors = output_profile_xml (profile);
+	g_list_free (profile);
+	profile = NULL;
+
+	if (!errors) {
+		profiler_xml_error ();
+		return;
+	}
+	
+	g_hash_table_foreach (prof->methods, (GHFunc)build_newobj_profile, &profile);
+	errors = output_newobj_profile_xml (profile);
+	g_list_free (profile);
+
+	if (!errors) {
+		profiler_xml_error ();
+		return;
+	}
+
+	length = fprintf (xml_file, "</profile>");
+	if (length < 0)
+		profiler_xml_error ();
+
+	fclose (xml_file);
+	
+}
+
+static void
+simple_shutdown (MonoProfiler *prof)
+{	
 	GList *profile = NULL;
 	MonoProfiler *tprof;
 	GSList *tmp;
 	char *str;
 
+	if (profiler_xml_file && strcmp (profiler_xml_file, "")) {
+		simple_shutdown_xml (prof);
+		return;
+	}
+
 	for (tmp = prof->per_thread; tmp; tmp = tmp->next) {
 		tprof = tmp->data;
 		merge_thread_data (prof, tprof);
@@ -1056,11 +1287,17 @@
 			else
 			   if (!strcmp (arg, "-alloc"))
 				   flags &= ~MONO_PROFILE_ALLOCATIONS;
-			   else {
-				   fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
-				   return;
-			   }
+			   else
+				   if (!strcmp (arg, "xml"))
+					   profiler_xml_file = "profile.xml";
+				   else if (!strncmp (arg, "xml=", 4))
+					   profiler_xml_file = arg + 4;
+				   else {
+					   fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
+					   return;
+				   }
 		}
+
 	}
 
 	prof = create_profiler ();


More information about the Mono-devel-list mailing list