#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>
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));
agent->value = NULL;
agent->value_size = 0;
agent->index = counters_index++;
+ agent->emitted = 0;
agent->next = NULL;
if (!counters) {
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);
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
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);
EXIT_LOG (logbuffer);
safe_dump (profiler, ensure_logbuf (0));
+
+ mono_mutex_unlock (&counters_mutex);
}
#endif /* DISABLE_HELPER_THREAD */
static int valid_mask = 0;
static int set_mask = 0;
+static GSList *register_callbacks = NULL;
+
static void initialize_system_counters (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)
counters = counter;
}
+ for (register_callback = register_callbacks; register_callback; register_callback = register_callback->next)
+ ((MonoCounterRegisterCallback)register_callback->data) (counter);
+
mono_mutex_unlock (&counters_mutex);
}
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);