[mono/mono] a57f9ce8: [runtime] JIT debugging option to optimize only single methods.

"Mark Probst ([email protected])" <[email protected]>
Newsgroups gmane.comp.gnome.mono.patches
Message-ID <00000141cde1f8ed-a8bd2935-5249-4269-b6ae-ad8e62ac0f11-000000@email.amazonses.com>
   Branch: refs/heads/master
     Home: https://github.com/mono/mono
  Compare: https://github.com/mono/mono/compare/b17461cb8a48...a57f9ce8a0c0

   Commit: a57f9ce8a0c0d3acb0606f63594398632fe3887e
   Author: Mark Probst <[email protected]> (schani)
     Date: 2013-10-18 23:19:00 GMT
      URL: https://github.com/mono/mono/commit/a57f9ce8a0c0d3acb0606f63594398632fe3887e

[runtime] JIT debugging option to optimize only single methods.

The --single-method option run regression tests from an assembly, like
--regression.  Instead of going through a list of optimizations,
however, it takes one optimization combination, runs all tests with
all optimizations turned off, while gathering a list of which methods
were jitted.  Then, for each jitted method, it runs all tests again,
with the optimizations applied to only that one method, stopping as
soon as a test fails.  Example:

    mono --single-method=branch,peephole basic-float.exe

Changed paths:
  M mono/mini/driver.c
  M mono/mini/mini.c
  M mono/mini/mini.h

Modified: mono/mini/driver.c
===================================================================
@@ -342,18 +342,128 @@
 }
 #endif
 
+static gboolean do_single_method_regression = FALSE;
+static guint32 single_method_regression_opt;
+static MonoMethod *current_single_method = NULL;
+static GSList *single_method_list = NULL;
+static GHashTable *single_method_hash = NULL;
+
+guint32
+mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt)
+{
+	g_assert (method);
+
+	if (!do_single_method_regression)
+		return default_opt;
+	if (!current_single_method) {
+		if (!single_method_hash)
+			single_method_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+		if (!g_hash_table_lookup (single_method_hash, method)) {
+			g_hash_table_insert (single_method_hash, method, method);
+			single_method_list = g_slist_prepend (single_method_list, method);
+		}
+		return default_opt;
+	}
+	if (method == current_single_method)
+		return single_method_regression_opt;
+	return default_opt;
+}
+
+static void
+mini_regression_step (MonoImage *image, int verbose, int *total_run, int *total,
+		guint32 opt_flags,
+		GTimer *timer, MonoDomain *domain)
+{
+	int result, expected, failed, cfailed, run, code_size;
+	TestMethod func;
+	double elapsed, comp_time, start_time;
+	char *n;
+	int i;
+
+	mono_set_defaults (verbose, opt_flags);
+	n = opt_descr (opt_flags);
+	g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
+	g_free (n);
+	cfailed = failed = run = code_size = 0;
+	comp_time = elapsed = 0.0;
+
+	/* fixme: ugly hack - delete all previously compiled methods */
+	g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
+	domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+	mono_internal_hash_table_destroy (&(domain->jit_code_hash));
+	mono_jit_code_hash_init (&(domain->jit_code_hash));
+
+	g_timer_start (timer);
+	if (mini_stats_fd)
+		fprintf (mini_stats_fd, "[");
+	for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
+		MonoMethod *method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+		if (!method)
+			continue;
+		if (strncmp (method->name, "test_", 5) == 0) {
+			MonoCompile *cfg;
+
+			expected = atoi (method->name + 5);
+			run++;
+			start_time = g_timer_elapsed (timer, NULL);
+			comp_time -= start_time;
+			cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, opt_flags), mono_get_root_domain (), TRUE, FALSE, 0);
+			comp_time += g_timer_elapsed (timer, NULL);
+			if (cfg->exception_type == MONO_EXCEPTION_NONE) {
+				if (verbose >= 2)
+					g_print ("Running '%s' ...\n", method->name);
+#ifdef MONO_USE_AOT_COMPILER
+				if ((func = mono_aot_get_method (mono_get_root_domain (), method)))
+					;
+				else
+#endif
+					func = (TestMethod)(gpointer)cfg->native_code;
+				func = (TestMethod)mono_create_ftnptr (mono_get_root_domain (), func);
+				result = func ();
+				if (result != expected) {
+					failed++;
+					g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
+				}
+				code_size += cfg->code_len;
+				mono_destroy_compile (cfg);
+
+			} else {
+				cfailed++;
+				if (verbose)
+					g_print ("Test '%s' failed compilation.\n", method->name);
+			}
+			if (mini_stats_fd)
+				fprintf (mini_stats_fd, "%f, ",
+						g_timer_elapsed (timer, NULL) - start_time);
+		}
+	}
+	if (mini_stats_fd)
+		fprintf (mini_stats_fd, "],\n");
+	g_timer_stop (timer);
+	elapsed = g_timer_elapsed (timer, NULL);
+	if (failed > 0 || cfailed > 0){
+		g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
+				run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
+	} else {
+		g_print ("Results: total tests: %d, all pass \n",  run);
+	}
+
+	g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed,
+			elapsed - comp_time, comp_time, code_size);
+	*total += failed + cfailed;
+	*total_run += run;
+}
+
 static int
 mini_regression (MonoImage *image, int verbose, int *total_run)
 {
-	guint32 i, opt, opt_flags;
+	guint32 i, opt;
 	MonoMethod *method;
-	MonoCompile *cfg;
 	char *n;
-	int result, expected, failed, cfailed, run, code_size, total;
-	TestMethod func;
 	GTimer *timer = g_timer_new ();
 	MonoDomain *domain = mono_domain_get ();
 	guint32 exclude = 0;
+	int total;
 
 	/* Note: mono_hwcap_init () called in mono_init () before we get here. */
 	mono_arch_cpu_optimizations (&exclude);
@@ -363,7 +473,7 @@
 
 		fprintf (mini_stats_fd, "$graph->set_legend(qw(");
 		for (opt = 0; opt < G_N_ELEMENTS (opt_sets); opt++) {
-			opt_flags = opt_sets [opt];
+			guint32 opt_flags = opt_sets [opt];
 			n = opt_descr (opt_flags);
 			if (!n [0])
 				n = (char *)"none";
@@ -396,80 +506,37 @@
 
 	total = 0;
 	*total_run = 0;
-	for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
-		double elapsed, comp_time, start_time;
-
-		opt_flags = opt_sets [opt] & ~exclude;
-		mono_set_defaults (verbose, opt_flags);
-		n = opt_descr (opt_flags);
-		g_print ("Test run: image=%s, opts=%s\n", mono_image_get_filename (image), n);
-		g_free (n);
-		cfailed = failed = run = code_size = 0;
-		comp_time = elapsed = 0.0;
-
-		/* fixme: ugly hack - delete all previously compiled methods */
-		g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
-		domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-		mono_internal_hash_table_destroy (&(domain->jit_code_hash));
-		mono_jit_code_hash_init (&(domain->jit_code_hash));
-
-		g_timer_start (timer);
-		if (mini_stats_fd)
-			fprintf (mini_stats_fd, "[");
-		for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-			method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
-			if (!method)
-				continue;
-			if (strncmp (method->name, "test_", 5) == 0) {
-				expected = atoi (method->name + 5);
-				run++;
-				start_time = g_timer_elapsed (timer, NULL);
-				comp_time -= start_time; 
-				cfg = mini_method_compile (method, opt_flags, mono_get_root_domain (), TRUE, FALSE, 0);
-				comp_time += g_timer_elapsed (timer, NULL);
-				if (cfg->exception_type == MONO_EXCEPTION_NONE) {
-					if (verbose >= 2)
-						g_print ("Running '%s' ...\n", method->name);
-#ifdef MONO_USE_AOT_COMPILER
-					if ((func = mono_aot_get_method (mono_get_root_domain (), method)))
-						;
-					else
-#endif
-						func = (TestMethod)(gpointer)cfg->native_code;
-					func = (TestMethod)mono_create_ftnptr (mono_get_root_domain (), func);
-					result = func ();
-					if (result != expected) {
-						failed++;
-						g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
-					}
-					code_size += cfg->code_len;
-					mono_destroy_compile (cfg);
-
-				} else {
-					cfailed++;
-					if (verbose)
-						g_print ("Test '%s' failed compilation.\n", method->name);
-				}
-				if (mini_stats_fd)
-					fprintf (mini_stats_fd, "%f, ", 
-						 g_timer_elapsed (timer, NULL) - start_time);
-			}
+	if (do_single_method_regression) {
+		GSList *iter;
+
+		mini_regression_step (image, verbose, total_run, &total,
+				0,
+				timer, domain);
+		if (total)
+			return total;
+		g_print ("Single method regression: %d methods\n", g_slist_length (single_method_list));
+
+		for (iter = single_method_list; iter; iter = g_slist_next (iter)) {
+			char *method_name;
+
+			current_single_method = iter->data;
+
+			method_name = mono_method_full_name (current_single_method, TRUE);
+			g_print ("Current single method: %s\n", method_name);
+			g_free (method_name);
+
+			mini_regression_step (image, verbose, total_run, &total,
+					0,
+					timer, domain);
+			if (total)
+				return total;
 		}
-		if (mini_stats_fd)
-			fprintf (mini_stats_fd, "],\n");
-		g_timer_stop (timer);
-		elapsed = g_timer_elapsed (timer, NULL);
-		if (failed > 0 || cfailed > 0){
-			g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n", 
-				 run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
-		} else {
-			g_print ("Results: total tests: %d, all pass \n",  run);
+	} else {
+		for (opt = 0; opt < G_N_ELEMENTS (opt_sets); ++opt) {
+			mini_regression_step (image, verbose, total_run, &total,
+					opt_sets [opt] & ~exclude,
+					timer, domain);
 		}
-		
-		g_print ("Elapsed time: %f secs (%f, %f), Code size: %d\n\n", elapsed, 
-			 elapsed - comp_time, comp_time, code_size);
-		total += failed + cfailed;
-		*total_run += run;
 	}
 
 	if (mini_stats_fd) {
@@ -829,6 +896,7 @@
 enum {
 	DO_BENCH,
 	DO_REGRESSION,
+	DO_SINGLE_METHOD_REGRESSION,
 	DO_COMPILE,
 	DO_EXEC,
 	DO_DRAW,
@@ -888,7 +956,7 @@ enum {
 			g_print ("Compiling %d %s\n", count, desc);
 			g_free (desc);
 		}
-		cfg = mini_method_compile (method, args->opts, mono_get_root_domain (), FALSE, FALSE, 0);
+		cfg = mini_method_compile (method, mono_get_optimizations_for_method (method, args->opts), mono_get_root_domain (), FALSE, FALSE, 0);
 		if (cfg->exception_type != MONO_EXCEPTION_NONE) {
 			printf ("Compilation of %s failed with exception '%s':\n", mono_method_full_name (cfg->method, TRUE), cfg->exception_message);
 			fail_count ++;
@@ -1100,6 +1168,7 @@ static void main_thread_handler (gpointer user_data)
 		 "    --ncompile N           Number of times to compile METHOD (default: 1)\n"
 		 "    --print-vtable         Print the vtable of all used classes\n"
 		 "    --regression           Runs the regression test contained in the assembly\n"
+		 "    --single-method=OPTS   Runs regressions with only one method optimized with OPTS at any time\n"
 		 "    --statfile FILE        Sets the stat file to FILE\n"
 		 "    --stats                Print statistics about the JIT operations\n"
 		 "    --wapi=hps|semdel|seminfo IO-layer maintenance\n"
@@ -1486,6 +1555,11 @@ BOOL APIENTRY DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
 			break;
 		if (strcmp (argv [i], "--regression") == 0) {
 			action = DO_REGRESSION;
+		} else if (strncmp (argv [i], "--single-method=", 16) == 0) {
+			char *full_opts = g_strdup_printf ("-all,%s", argv [i] + 16);
+			action = DO_SINGLE_METHOD_REGRESSION;
+			single_method_regression_opt = parse_optimizations (full_opts);
+			g_free (full_opts);
 		} else if (strcmp (argv [i], "--verbose") == 0 || strcmp (argv [i], "-v") == 0) {
 			mini_verbose++;
 		} else if (strcmp (argv [i], "--version") == 0 || strcmp (argv [i], "-V") == 0) {
@@ -1878,6 +1952,8 @@ BOOL APIENTRY DllMain (HMODULE module_handle, DWORD reason, LPVOID reserved)
 	}
 	
 	switch (action) {
+	case DO_SINGLE_METHOD_REGRESSION:
+		do_single_method_regression = TRUE;
 	case DO_REGRESSION:
 		if (mini_regression_list (mini_verbose, argc -i, argv + i)) {
 			g_print ("Regression ERRORS!\n");

Modified: mono/mini/mini.c
===================================================================
@@ -6138,7 +6138,7 @@ void *mono_global_codeman_reserve (int size)
 	MonoException *ex = NULL;
 	gpointer code;
 
-	code = mono_jit_compile_method_with_opt (method, default_opt, &ex);
+	code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex);
 	if (!code) {
 		g_assert (ex);
 		mono_raise_exception (ex);
@@ -6349,7 +6349,7 @@ void *mono_global_codeman_reserve (int size)
 		if (callee) {
 			MonoException *jit_ex = NULL;
 
-			info->compiled_method = mono_jit_compile_method_with_opt (callee, default_opt, &jit_ex);
+			info->compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
 			if (!info->compiled_method) {
 				g_free (info);
 				g_assert (jit_ex);

Modified: mono/mini/mini.h
===================================================================
@@ -1875,6 +1875,7 @@ enum {
 /* helper methods */
 void      mono_disable_optimizations       (guint32 opts) MONO_INTERNAL;
 void      mono_set_optimizations           (guint32 opts) MONO_INTERNAL;
+guint32   mono_get_optimizations_for_method (MonoMethod *method, guint32 default_opt) MONO_INTERNAL;
 void      mono_set_verbose_level           (guint32 level) MONO_INTERNAL;
 MonoJumpInfoToken* mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token) MONO_INTERNAL;
 MonoJumpInfoToken* mono_jump_info_token_new2 (MonoMemPool *mp, MonoImage *image, guint32 token, MonoGenericContext *context) MONO_INTERNAL;


_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.