[profiler] Some improvements to the code coverage API.
authorAlex Rønne Petersen <alexrp@xamarin.com>
Sat, 5 Aug 2017 16:18:54 +0000 (18:18 +0200)
committerAlex Rønne Petersen <alpeters@microsoft.com>
Mon, 7 Aug 2017 20:38:26 +0000 (22:38 +0200)
Code coverage must now be explicitly enabled. This simplifies initialization
of some coverage-related structures and also lets us enable debug info which
is needed to produce good data.

Also change the signature of mono_profiler_get_coverage_data so it returns a
value indicating whether coverage data was available.

mono/metadata/profiler-private.h
mono/metadata/profiler.c
mono/metadata/profiler.h
mono/profiler/log.c

index 293c2bd05e974436c41b8987c85a7c585485a11b..340a70d3059c5f03c2d6250bb1deb620f9518329 100644 (file)
@@ -10,7 +10,6 @@
 #define MONO_PROFILER_UNSTABLE_GC_ROOTS
 #include <mono/metadata/profiler.h>
 #include <mono/utils/mono-context.h>
-#include <mono/utils/mono-lazy-init.h>
 #include <mono/utils/mono-os-mutex.h>
 #include <mono/utils/mono-os-semaphore.h>
 
@@ -46,7 +45,7 @@ typedef struct {
 
        MonoProfilerHandle profilers;
 
-       mono_lazy_init_t coverage_status;
+       gboolean code_coverage;
        mono_mutex_t coverage_mutex;
        GHashTable *coverage_hash;
 
@@ -106,7 +105,6 @@ mono_profiler_installed (void)
 }
 
 MonoProfilerCoverageInfo *mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries);
-void mono_profiler_coverage_free (MonoMethod *method);
 
 struct _MonoProfilerCallContext {
        /*
index fa3f4eec9d1a6dfff683034165b8f94baaaba0b8..0f429f607ff9a6c2b3823f3fd43208103455ffa2 100644 (file)
@@ -163,17 +163,19 @@ mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfi
        InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
 }
 
-static void
-initialize_coverage (void)
+mono_bool
+mono_profiler_enable_coverage (void)
 {
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
        mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
        mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
-}
 
-static void
-lazy_initialize_coverage (void)
-{
-       mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage);
+       if (!mono_debug_enabled ())
+               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
+
+       return TRUE;
 }
 
 static void
@@ -188,10 +190,11 @@ coverage_unlock (void)
        mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
 }
 
-void
+mono_bool
 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
 {
-       lazy_initialize_coverage ();
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
        coverage_lock ();
 
@@ -200,7 +203,7 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
        coverage_unlock ();
 
        if (!info)
-               return;
+               return FALSE;
 
        MonoError error;
        MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
@@ -245,12 +248,15 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
        }
 
        mono_metadata_free_mh (header);
+
+       return TRUE;
 }
 
 MonoProfilerCoverageInfo *
 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
 {
-       lazy_initialize_coverage ();
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
        gboolean cover = FALSE;
 
@@ -277,23 +283,6 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
        return info;
 }
 
-void
-mono_profiler_coverage_free (MonoMethod *method)
-{
-       lazy_initialize_coverage ();
-
-       coverage_lock ();
-
-       MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
-
-       if (info) {
-               g_hash_table_remove (mono_profiler_state.coverage_hash, method);
-               g_free (info);
-       }
-
-       coverage_unlock ();
-}
-
 mono_bool
 mono_profiler_enable_sampling (MonoProfilerHandle handle)
 {
index 133fec753d9d1be212209078c420a629e80fca10..76759d9f845d22acc3e9f14893332e73b74437c4 100644 (file)
@@ -42,7 +42,9 @@ typedef struct _MonoProfilerDesc *MonoProfilerHandle;
 
 /*
  * Installs a profiler and returns a handle for it. The handle is used with the
- * other functions in the profiler API (e.g. for setting up callbacks).
+ * other functions in the profiler API (e.g. for setting up callbacks). The
+ * given structure pointer will be passed to all callbacks from the profiler
+ * API. It can be NULL.
  *
  * This function may only be called from your profiler's init function.
  *
@@ -61,6 +63,19 @@ typedef struct _MonoProfilerDesc *MonoProfilerHandle;
  */
 MONO_API MonoProfilerHandle mono_profiler_create (MonoProfiler *prof);
 
+/*
+ * Enables support for code coverage instrumentation. At the moment, this means
+ * enabling the debug info subsystem. If you do not call this function, you
+ * will not be able to use mono_profiler_get_coverage_data. Returns TRUE if
+ * code coverage support was enabled, or FALSE if the function was called too
+ * late for this to be possible.
+ *
+ * This function may only be called from your profiler's init function.
+ *
+ * This function is not async safe.
+ */
+MONO_API mono_bool mono_profiler_enable_coverage (void);
+
 typedef mono_bool (*MonoProfilerCoverageFilterCallback) (MonoProfiler *prof, MonoMethod *method);
 
 /*
@@ -91,11 +106,16 @@ typedef void (*MonoProfilerCoverageCallback) (MonoProfiler *prof, const MonoProf
 
 /*
  * Retrieves all coverage data for the specified method and invokes the given
- * callback for each entry.
+ * callback for each entry. Source location information will only be filled out
+ * if the given method has debug info available. Returns TRUE if the given
+ * method was instrumented for code coverage; otherwise, FALSE.
+ *
+ * Please note that the structure passed to the callback is only valid for the
+ * duration of the callback.
  *
  * This function is not async safe.
  */
-MONO_API void mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb);
+MONO_API mono_bool mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb);
 
 typedef enum {
        /*
index 90f7309884796a55ac57dfb19aa89a76a192bffd..3d4c147cdaebf2d55c27fc10b6bc1b6b64382632 100644 (file)
@@ -4738,8 +4738,10 @@ mono_profiler_init_log (const char *desc)
                mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave);
        }
 
-       if (log_config.collect_coverage)
+       if (log_config.collect_coverage) {
+               mono_profiler_enable_coverage ();
                mono_profiler_set_coverage_filter_callback (handle, coverage_filter);
+       }
 
        mono_profiler_enable_allocations ();
        mono_profiler_enable_sampling (handle);