[counters,proflog] Add mono_counters_on_register/delete callbacks + Use them in proflog
authorLudovic Henry <ludovic.henry@xamarin.com>
Fri, 12 Sep 2014 18:38:03 +0000 (14:38 -0400)
committerLudovic Henry <ludovic.henry@xamarin.com>
Tue, 11 Nov 2014 18:40:29 +0000 (13:40 -0500)
This is used for counters that are defined after runtime initialization. It implies that TYPE_SAMPLE_COUNTERS_DESC can now be emitted at any time, and not only once.

mono/profiler/proflog.c
mono/utils/mono-counters.c
mono/utils/mono-counters.h

index 70e99112049f5a1c1f7b43e8c2d6c0ddb0feec7a..80a06cd933d6c2c9bca33a99250c0e0b3da4e8a7 100644 (file)
@@ -16,6 +16,7 @@
 #include <mono/utils/atomic.h>
 #include <mono/utils/mono-membar.h>
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-mutex.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -1960,21 +1961,35 @@ typedef struct MonoCounterAgent {
        void *value;
        size_t value_size;
        short index;
+       short emitted;
        struct MonoCounterAgent *next;
 } MonoCounterAgent;
 
 static MonoCounterAgent* counters;
 static gboolean counters_initialized = FALSE;
 static int counters_index = 1;
+static mono_mutex_t counters_mutex;
 
-static mono_bool
-counters_init_add_counter (MonoCounter *counter, gpointer data)
+static void
+counters_add_agent (MonoCounter *counter)
 {
        MonoCounterAgent *agent, *item;
 
+       if (!counters_initialized)
+               return;
+
+       mono_mutex_lock (&counters_mutex);
+
        for (agent = counters; agent; agent = agent->next) {
-               if (agent->counter == counter)
-                       return TRUE;
+               if (agent->counter == counter) {
+                       agent->value_size = 0;
+                       if (agent->value) {
+                               free (agent->value);
+                               agent->value = NULL;
+                       }
+                       mono_mutex_unlock (&counters_mutex);
+                       return;
+               }
        }
 
        agent = malloc (sizeof (MonoCounterAgent));
@@ -1982,6 +1997,7 @@ counters_init_add_counter (MonoCounter *counter, gpointer data)
        agent->value = NULL;
        agent->value_size = 0;
        agent->index = counters_index++;
+       agent->emitted = 0;
        agent->next = NULL;
 
        if (!counters) {
@@ -1993,29 +2009,63 @@ counters_init_add_counter (MonoCounter *counter, gpointer data)
                item->next = agent;
        }
 
+       mono_mutex_unlock (&counters_mutex);
+}
+
+static mono_bool
+counters_init_foreach_callback (MonoCounter *counter, gpointer data)
+{
+       counters_add_agent (counter);
        return TRUE;
 }
 
 static void
 counters_init (MonoProfiler *profiler)
+{
+       assert (!counters_initialized);
+
+       mono_mutex_init (&counters_mutex);
+
+       counters_initialized = TRUE;
+
+       mono_counters_on_register (&counters_add_agent);
+       mono_counters_foreach (counters_init_foreach_callback, NULL);
+}
+
+static void
+counters_emit (MonoProfiler *profiler)
 {
        MonoCounterAgent *agent;
        LogBuffer *logbuffer;
        int size = 1 + 5, len = 0;
 
-       mono_counters_foreach (counters_init_add_counter, NULL);
+       if (!counters_initialized)
+               return;
+
+       mono_mutex_lock (&counters_mutex);
 
        for (agent = counters; agent; agent = agent->next) {
+               if (agent->emitted)
+                       continue;
+
                size += strlen (mono_counter_get_name (agent->counter)) + 1 + 5 * 5;
                len += 1;
        }
 
+       if (!len) {
+               mono_mutex_unlock (&counters_mutex);
+               return;
+       }
+
        logbuffer = ensure_logbuf (size);
 
        ENTER_LOG (logbuffer, "counters");
        emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
        emit_value (logbuffer, len);
        for (agent = counters; agent; agent = agent->next) {
+               if (agent->emitted)
+                       continue;
+
                const char *name = mono_counter_get_name (agent->counter);
                emit_value (logbuffer, mono_counter_get_section (agent->counter));
                emit_string (logbuffer, name, strlen (name) + 1);
@@ -2023,10 +2073,14 @@ counters_init (MonoProfiler *profiler)
                emit_value (logbuffer, mono_counter_get_unit (agent->counter));
                emit_value (logbuffer, mono_counter_get_variance (agent->counter));
                emit_value (logbuffer, agent->index);
+
+               agent->emitted = 1;
        }
        EXIT_LOG (logbuffer);
 
-       counters_initialized = TRUE;
+       safe_dump (profiler, ensure_logbuf (0));
+
+       mono_mutex_unlock (&counters_mutex);
 }
 
 static void
@@ -2048,11 +2102,15 @@ counters_sample (MonoProfiler *profiler)
        if (!counters_initialized)
                return;
 
+       counters_emit (profiler);
+
        timestamp = (current_time () - start) / 1000/ 1000;
 
        buffer_size = 8;
        buffer = calloc (1, buffer_size);
 
+       mono_mutex_lock (&counters_mutex);
+
        size = 1 + 10 + 5;
        for (agent = counters; agent; agent = agent->next)
                size += 10 * 2 + mono_counter_get_size (agent->counter);
@@ -2146,6 +2204,8 @@ counters_sample (MonoProfiler *profiler)
        EXIT_LOG (logbuffer);
 
        safe_dump (profiler, ensure_logbuf (0));
+
+       mono_mutex_unlock (&counters_mutex);
 }
 
 #endif /* DISABLE_HELPER_THREAD */
index 97d15e03f888df00196bd53ed901bdde121d0e94..1e0840c6b04a7b539d5854aadbd3874edf8afc2d 100644 (file)
@@ -30,6 +30,8 @@ static volatile gboolean initialized = FALSE;
 static int valid_mask = 0;
 static int set_mask = 0;
 
+static GSList *register_callbacks = NULL;
+
 static void initialize_system_counters (void);
 
 /**
@@ -147,6 +149,7 @@ static void
 register_internal (const char *name, int type, void *addr, int size)
 {
        MonoCounter *counter;
+       GSList *register_callback;
 
        g_assert (size >= 0);
        if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
@@ -185,6 +188,9 @@ register_internal (const char *name, int type, void *addr, int size)
                counters = counter;
        }
 
+       for (register_callback = register_callbacks; register_callback; register_callback = register_callback->next)
+               ((MonoCounterRegisterCallback)register_callback->data) (counter);
+
        mono_mutex_unlock (&counters_mutex);
 }
 
@@ -271,6 +277,25 @@ mono_counters_register_with_size (const char *name, int type, void *addr, int si
                register_internal (name, type, addr, size);
 }
 
+/**
+ * mono_counters_on_register
+ * @callback : function to callback when a counter is registered
+ *
+ * Add a callback that is going to be called when a counter is registered
+ */
+void
+mono_counters_on_register (MonoCounterRegisterCallback callback)
+{
+       if (!initialized) {
+               g_warning ("counters not enabled");
+               return;
+       }
+
+       mono_mutex_lock (&counters_mutex);
+       register_callbacks = g_slist_append (register_callbacks, callback);
+       mono_mutex_unlock (&counters_mutex);
+}
+
 typedef int (*IntFunc) (void);
 typedef guint (*UIntFunc) (void);
 typedef gint64 (*LongFunc) (void);
index e76e4468691264a3da0a6d99391d898c52117727..ac7c7df8f0cca364ffd58c837f72b67ef01a3648 100644 (file)
@@ -57,6 +57,9 @@ MONO_API void mono_counters_init (void);
 MONO_API void mono_counters_register (const char* descr, int type, void *addr);
 MONO_API void mono_counters_register_with_size (const char *name, int type, void *addr, int size);
 
+typedef void (*MonoCounterRegisterCallback) (MonoCounter*);
+MONO_API void mono_counters_on_register (MonoCounterRegisterCallback callback);
+
 /* 
  * Create a readable dump of the counters for section_mask sections (ORed section values)
  */