[runtime] Coverage profiler fixes (#5698)
authorZoltan Varga <vargaz@gmail.com>
Thu, 5 Oct 2017 15:15:36 +0000 (17:15 +0200)
committerGitHub <noreply@github.com>
Thu, 5 Oct 2017 15:15:36 +0000 (17:15 +0200)
* [runtime] Avoid collecting coverage data for wrappers.

* [runtime] Return sensible information for methods which have no coverage info in mono_profiler_get_coverage_data ().

* [profiler] Emit coverage info for uncovered methods as well.

mono/metadata/profiler.c
mono/profiler/coverage.c

index b10423120d43a649f8fd9a0c160a0fb3f307523f..9f65059f806699088b673fcf01a1896ae59a7576 100644 (file)
@@ -9,6 +9,7 @@
 #include <mono/metadata/mono-config-dirs.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/mono-config-dirs.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/profiler-private.h>
+#include <mono/metadata/debug-internals.h>
 #include <mono/utils/mono-dl.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-logger-internals.h>
 #include <mono/utils/mono-dl.h>
 #include <mono/utils/mono-error-internals.h>
 #include <mono/utils/mono-logger-internals.h>
@@ -208,9 +209,6 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
 
        coverage_unlock ();
 
 
        coverage_unlock ();
 
-       if (!info)
-               return FALSE;
-
        MonoError error;
        MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
        mono_error_assert_ok (&error);
        MonoError error;
        MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
        mono_error_assert_ok (&error);
@@ -221,6 +219,45 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
        const unsigned char *end = start + size;
        MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
 
        const unsigned char *end = start + size;
        MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
 
+       if (!info) {
+               char *source_file;
+               int i, n_il_offsets;
+               int *source_files;
+               GPtrArray *source_file_list;
+               MonoSymSeqPoint *sym_seq_points;
+
+               /* Return 0 counts for all locations */
+
+               mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
+               for (i = 0; i < n_il_offsets; ++i) {
+                       MonoSymSeqPoint *sp = &sym_seq_points [i];
+                       const char *srcfile = "";
+
+                       if (source_files [i] != -1) {
+                               MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
+                               srcfile = sinfo->source_file;
+                       }
+
+                       MonoProfilerCoverageData data = {
+                               .method = method,
+                               .il_offset = sp->il_offset,
+                               .counter = 0,
+                               .file_name = srcfile,
+                               .line = sp->line,
+                               .column = 0,
+                       };
+
+                       cb (handle->prof, &data);
+               }
+
+               g_free (source_files);
+               g_free (sym_seq_points);
+               g_ptr_array_free (source_file_list, TRUE);
+
+               mono_metadata_free_mh (header);
+               return TRUE;
+       }
+
        for (guint32 i = 0; i < info->entries; i++) {
                guchar *cil_code = info->data [i].cil_code;
 
        for (guint32 i = 0; i < info->entries; i++) {
                guchar *cil_code = info->data [i].cil_code;
 
@@ -264,6 +301,9 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
        if (!mono_profiler_state.code_coverage)
                return FALSE;
 
        if (!mono_profiler_state.code_coverage)
                return FALSE;
 
+       if (method->wrapper_type)
+               return FALSE;
+
        gboolean cover = FALSE;
 
        for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
        gboolean cover = FALSE;
 
        for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
index de8f5207b0afde32a72ae0666d796726ad1ce4fa..f88e49df626f33be6d8f9f94b36ad52d4e44ef8d 100644 (file)
@@ -112,6 +112,8 @@ struct _MonoProfiler {
 
        MonoConcurrentHashTable *image_to_methods;
 
 
        MonoConcurrentHashTable *image_to_methods;
 
+       GHashTable *uncovered_methods;
+
        guint32 previous_offset;
 };
 
        guint32 previous_offset;
 };
 
@@ -357,7 +359,30 @@ dump_classes_for_image (gpointer key, gpointer value, gpointer userdata)
        class_name = mono_type_get_name (mono_class_get_type (klass));
 
        number_of_methods = mono_class_num_methods (klass);
        class_name = mono_type_get_name (mono_class_get_type (klass));
 
        number_of_methods = mono_class_num_methods (klass);
-       fully_covered = count_queue (class_methods);
+
+       GHashTable *covered_methods = g_hash_table_new (NULL, NULL);
+       int count = 0;
+       {
+               MonoLockFreeQueueNode *node;
+               guint count = 0;
+
+               while ((node = mono_lock_free_queue_dequeue (class_methods))) {
+                       MethodNode *mnode = (MethodNode*)node;
+                       g_hash_table_insert (covered_methods, mnode->method, mnode->method);
+                       count++;
+                       mono_thread_hazardous_try_free (node, g_free);
+               }
+       }
+       fully_covered = count;
+
+       gpointer iter = NULL;
+       MonoMethod *method;
+       while ((method = mono_class_get_methods (klass, &iter))) {
+               if (!g_hash_table_lookup (covered_methods, method))
+                       g_hash_table_insert (coverage_profiler.uncovered_methods, method, method);
+       }
+       g_hash_table_destroy (covered_methods);
+
        /* We don't handle partial covered yet */
        partially_covered = 0;
 
        /* We don't handle partial covered yet */
        partially_covered = 0;
 
@@ -428,6 +453,7 @@ dump_coverage (void)
        mono_os_mutex_lock (&coverage_profiler.mutex);
        mono_conc_hashtable_foreach (coverage_profiler.assemblies, dump_assembly, NULL);
        mono_conc_hashtable_foreach (coverage_profiler.methods, dump_method, NULL);
        mono_os_mutex_lock (&coverage_profiler.mutex);
        mono_conc_hashtable_foreach (coverage_profiler.assemblies, dump_assembly, NULL);
        mono_conc_hashtable_foreach (coverage_profiler.methods, dump_method, NULL);
+       g_hash_table_foreach (coverage_profiler.uncovered_methods, dump_method, NULL);
        mono_os_mutex_unlock (&coverage_profiler.mutex);
 
        fprintf (coverage_profiler.file, "</coverage>\n");
        mono_os_mutex_unlock (&coverage_profiler.mutex);
 
        fprintf (coverage_profiler.file, "</coverage>\n");
@@ -901,6 +927,7 @@ mono_profiler_init_coverage (const char *desc)
        coverage_profiler.classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.filtered_classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.image_to_methods = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.filtered_classes = mono_conc_hashtable_new (NULL, NULL);
        coverage_profiler.image_to_methods = mono_conc_hashtable_new (NULL, NULL);
+       coverage_profiler.uncovered_methods = g_hash_table_new (NULL, NULL);
        init_suppressed_assemblies ();
 
        coverage_profiler.filters = filters;
        init_suppressed_assemblies ();
 
        coverage_profiler.filters = filters;