Skip to content

Instantly share code, notes, and snippets.

@luhenry
Created March 20, 2014 21:40
Show Gist options
  • Save luhenry/9674492 to your computer and use it in GitHub Desktop.
Save luhenry/9674492 to your computer and use it in GitHub Desktop.
diff --git a/mono/utils/mono-counters-agent.c b/mono/utils/mono-counters-agent.c
index 76ce467..994150e 100644
--- a/mono/utils/mono-counters-agent.c
+++ b/mono/utils/mono-counters-agent.c
@@ -18,12 +18,14 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/select.h>
#include "mono-counters.h"
#include "mono-counters-internals.h"
#include "mono-counters-agent.h"
#include "mono-time.h"
#include "mono-threads.h"
+#define MONO_COUNTERS_AGENT_PROTOCOL_VERSION (0 << 8 | 1)
/**
* Protocol :
@@ -51,31 +53,29 @@ typedef struct MonoCounterAgent {
static const char *inspector_ip;
static int inspector_port;
-static int frequency;
+static gint64 interval;
static GSList* counters;
static gboolean agent_running;
+static short current_index = 0;
+
static int
parse_counters_all (MonoCounter* counter, void** args)
{
- static short index = 0;
-
MonoCounterAgent* _counter = g_malloc(sizeof(MonoCounterAgent));
_counter->counter = counter;
_counter->value = NULL;
- _counter->index = index;
+ _counter->index = current_index++;
counters = g_slist_append (counters, _counter);
- index += 1;
-
+
return 1;
}
static void
parse_counters_names (const char *counters_names)
{
- short index = 0;
gchar **names, **ptr;
if (!counters_names)
@@ -86,15 +86,15 @@ parse_counters_names (const char *counters_names)
for (ptr = names; *ptr; ++ptr) {
MonoCounterCategory category;
MonoCounter *counter;
- MonoCounterAgent *agent_counter;
+ MonoCounterAgent *counter_agent;
gchar **split = g_strsplit(*ptr, "/", 2);
if (!split[0] || !split[1]) {
g_warning ("Bad counter format '%s' use Category/Name", *ptr);
goto end;
}
-
+
category = mono_counters_category_name_to_id (split [0]);
- if (!category) {
+ if (category < 0) {
g_warning ("Category %s not found", split [0]);
goto end;
}
@@ -105,11 +105,12 @@ parse_counters_names (const char *counters_names)
goto end;
}
- agent_counter = g_new0 (MonoCounterAgent, 1);
- agent_counter->counter = counter;
- agent_counter->index = index++;
+ counter_agent = g_new0 (MonoCounterAgent, 1);
+ counter_agent->counter = counter;
+ counter_agent->value = NULL;
+ counter_agent->index = current_index++;
- counters = g_slist_append (counters, agent_counter);
+ counters = g_slist_append (counters, counter_agent);
end:
g_strfreev(split);
@@ -142,7 +143,7 @@ static gboolean
write_buffer_to_socket (int fd, const char* buffer, size_t size)
{
size_t sent = 0;
-
+
while (sent < size) {
ssize_t res = send (fd, buffer + sent, size - sent, 0);
if (res <= 0)
@@ -153,92 +154,344 @@ write_buffer_to_socket (int fd, const char* buffer, size_t size)
return TRUE;
}
-static void*
-mono_counters_agent_sampling_thread (void* ptr)
+static gboolean
+read_socket_to_buffer (int fd, const char* buffer, size_t size)
+{
+ size_t recvd = 0;
+
+ while (recvd < size) {
+ ssize_t res = recv (fd, buffer + recvd, size - recvd, 0);
+ if (res <= 0)
+ return FALSE;
+ recvd += res;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+write_counter_agent_header (int socketfd, MonoCounterAgent *counter_agent)
{
+ int len = strlen (counter_agent->counter->name);
+
+ if (!write_buffer_to_socket(socketfd, (char*)&counter_agent->counter->category, 4)
+ || !write_buffer_to_socket (socketfd, (char*)&len, 4)
+ || !write_buffer_to_socket (socketfd, (char*) counter_agent->counter->name, len)
+ || !write_buffer_to_socket (socketfd, (char*)&counter_agent->counter->type, 4)
+ || !write_buffer_to_socket (socketfd, (char*)&counter_agent->counter->unit, 4)
+ || !write_buffer_to_socket (socketfd, (char*)&counter_agent->counter->variance, 4)
+ || !write_buffer_to_socket (socketfd, (char*)&counter_agent->index, 2))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+write_counter_agent_headers (int socketfd)
+{
+ short count = 0;
GSList *item;
+
+ for (item = counters; item; item = item->next)
+ ++count;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&count, 2))
+ return FALSE;
+
+ for (item = counters; item; item = item->next) {
+ if (!write_counter_agent_header(socketfd, item->data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+write_counter_agent_value (int socketfd, MonoCounterAgent *counter_agent)
+{
+ return TRUE;
+}
+
+static gboolean
+do_hello (int socketfd)
+{
+ char cmd = 0;
+ short version = MONO_COUNTERS_AGENT_PROTOCOL_VERSION;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&cmd, 1))
+ return FALSE;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&version, 2))
+ return FALSE;
+
+ if (!write_counter_agent_headers (socketfd))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+do_list_counters (int socketfd)
+{
+ char cmd = 1;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&cmd, 1))
+ return FALSE;
+
+ if (!write_counter_agent_headers (socketfd))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+do_add_counter (int socketfd)
+{
+ char cmd = 2;
+ int len;
+ char *category, *name;
+ char status;
+ MonoCounterCategory category_id;
+ MonoCounter *counter;
+ MonoCounterAgent *counter_agent, *counter_agent_tmp;
+ gboolean already_exists;
+ GSList *item;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&cmd, 1))
+ return FALSE;
+
+ if (!read_socket_to_buffer(socketfd, (char*)&len, 4))
+ return FALSE;
+
+ category = g_malloc(len + 1);
+ if (!read_socket_to_buffer(socketfd, category, len))
+ return FALSE;
+ category[len] = '\0';
+
+ if (!read_socket_to_buffer(socketfd, (char*)&len, 4))
+ return FALSE;
+
+ name = g_malloc(len + 1);
+ if (!read_socket_to_buffer(socketfd, name, len))
+ return FALSE;
+ name[len] = '\0';
+
+ category_id = mono_counters_category_name_to_id(category);
+ if (category < 0)
+ status = MONO_COUNTERS_AGENT_STATUS_NOTFOUND;
+ else {
+ counter = mono_counters_get(category_id, name);
+ if (!counter) {
+ status = MONO_COUNTERS_AGENT_STATUS_NOTFOUND;
+ } else {
+ counter_agent = g_new0 (MonoCounterAgent, 1);
+ counter_agent->counter = counter;
+ counter_agent->value = NULL;
+ counter_agent->index = current_index++;
+
+ if (!counters) {
+ counters = g_slist_append (NULL, counter_agent);
+ status = MONO_COUNTERS_AGENT_STATUS_OK;
+ } else {
+ for (item = counters, already_exists = FALSE; item && !already_exists; item = item->next) {
+ counter_agent_tmp = item->data;
+ if (counter_agent_tmp->counter->category == category_id && strcmp(counter_agent_tmp->counter->name, name) == 0) {
+ already_exists = TRUE;
+ }
+ }
+
+ if (!already_exists) {
+ counters = g_slist_append (counters, counter_agent);
+ status = MONO_COUNTERS_AGENT_STATUS_OK;
+ } else {
+ g_free (counter_agent);
+ status = MONO_COUNTERS_AGENT_STATUS_EXISTING;
+ }
+ }
+ }
+ }
+
+ g_free(category);
+ g_free(name);
+
+ if (!write_buffer_to_socket(socketfd, &status, 1))
+ return FALSE;
+
+ if (status == MONO_COUNTERS_AGENT_STATUS_OK) {
+ if (!write_counter_agent_header(socketfd, counter_agent))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+do_remove_counter (int socketfd)
+{
+ char cmd = 3;
+ short index;
+ char status;
+ GSList *item;
+ MonoCounterAgent *counter_agent = NULL, *counter_agent_tmp;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&cmd, 1))
+ return FALSE;
+
+ if (!read_socket_to_buffer(socketfd, (char*)&index, 2))
+ return FALSE;
+
+ if (index < 0) {
+ g_slist_free(counters);
+ status = MONO_COUNTERS_AGENT_STATUS_OK;
+ } else {
+ for (item = counters; item; item = item->next) {
+ counter_agent_tmp = item->data;
+ if (counter_agent_tmp->index == index) {
+ counter_agent = counter_agent_tmp;
+ break;
+ }
+ }
+
+ if (counter_agent) {
+ g_slist_remove (counters, counter_agent);
+ g_free (counter_agent);
+
+ status = MONO_COUNTERS_AGENT_STATUS_OK;
+ } else {
+ status = MONO_COUNTERS_AGENT_STATUS_NOTFOUND;
+ }
+ }
+
+ return write_buffer_to_socket(socketfd, &status, 1);
+}
+
+static gboolean
+do_sampling (int socketfd)
+{
+ char cmd = 4;
char buffer[8];
- int socketfd = -1;
- short count = 0;
+ GSList *item;
+ MonoCounterAgent *counter_agent;
+
+ if (!write_buffer_to_socket (socketfd, (char*)&cmd, 1))
+ return FALSE;
+
+ gint64 timestamp = mono_100ns_datetime ();
+ if (!write_buffer_to_socket (socketfd, (char*)&timestamp, 8))
+ return FALSE;
+
+ for (item = counters; item; item = item->next) {
+ counter_agent = item->data;
+
+ if (!counter_agent)
+ continue;
+
+ int size = mono_counters_size (counter_agent->counter);
+ if (size < 0)
+ return FALSE;
+
+ if (mono_counters_sample (counter_agent->counter, buffer, size) != size)
+ return FALSE;
+
+ if (!counter_agent->value)
+ counter_agent->value = g_malloc (size);
+ else if (memcmp (counter_agent->value, buffer, size) == 0)
+ continue;
+
+ memcpy (counter_agent->value, buffer, size);
+
+ if (!write_buffer_to_socket (socketfd, (char*)&counter_agent->index, 2)
+ || !write_buffer_to_socket (socketfd, (char*)&size, 2)
+ || !write_buffer_to_socket (socketfd, (char*) buffer, size))
+ return FALSE;
+ }
+
+ short end = -1;
+ if (!write_buffer_to_socket (socketfd, (char*)&end, 2))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void*
+mono_counters_agent_sampling_thread (void* ptr)
+{
+ int socketfd = -1, ret;
struct sockaddr_in inspector_addr;
-
+ struct timeval timeout;
+ fd_set socketfd_set;
+ gint64 last_sampling = 0, now;
+ char cmd;
+
if ((socketfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
g_warning ("mono-counters-agent: error with socket : %s", strerror (errno));
return NULL;
}
-
+
memset (&inspector_addr, 0, sizeof (inspector_addr));
-
+
inspector_addr.sin_family = AF_INET;
inspector_addr.sin_port = htons (inspector_port);
-
+
if (!inet_pton (AF_INET, inspector_ip, &inspector_addr.sin_addr)) {
g_warning ("mono-counters-agent: error with inet_pton : %s", strerror (errno));
goto cleanup;
}
-
- if (connect(socketfd, (struct sockaddr*)&inspector_addr, sizeof(inspector_addr)) < 0) {
+
+ if (connect (socketfd, (struct sockaddr*)&inspector_addr, sizeof(inspector_addr)) < 0) {
g_warning ("mono-counters-agent: error with connect : %s", strerror(errno));
goto cleanup;
}
- for (item = counters; item; item = item->next)
- ++count;
+ FD_ZERO (&socketfd_set);
- if (!write_buffer_to_socket (socketfd, (char*)&count, 2))
+ if (!do_hello(socketfd))
goto cleanup;
- for (item = counters; item; item = item->next) {
- MonoCounterAgent* counter = item->data;
-
- int len = strlen (counter->counter->name);
-
- if (!write_buffer_to_socket(socketfd, (char*)&counter->counter->category, 4)
- || !write_buffer_to_socket (socketfd, (char*)&len, 4)
- || !write_buffer_to_socket (socketfd, (char*)counter->counter->name, len)
- || !write_buffer_to_socket (socketfd, (char*)&counter->counter->type, 4)
- || !write_buffer_to_socket (socketfd, (char*)&counter->counter->unit, 4)
- || !write_buffer_to_socket (socketfd, (char*)&counter->counter->variance, 4)
- || !write_buffer_to_socket (socketfd, (char*)&counter->index, 2))
- goto cleanup;
- }
-
for (;;) {
- gint64 timestamp = mono_100ns_ticks ();
- if (!write_buffer_to_socket (socketfd, (char*)&timestamp, 8))
- goto cleanup;
+ now = mono_100ns_datetime();
+ if (last_sampling == 0 || now > last_sampling + interval * 10000) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ } else {
+ timeout.tv_sec = ((last_sampling + interval * 10000 - now) / 10) / 1000000;
+ timeout.tv_usec = ((last_sampling + interval * 10000 - now) / 10) % 1000000;
+ }
- for (item = counters; item; item = item->next) {
- MonoCounterAgent* counter = item->data;
+ FD_SET (socketfd, &socketfd_set);
- if (!counter)
+ if ((ret = select (socketfd + 1, &socketfd_set, NULL, NULL, &timeout)) < 0) {
+ if (errno == EINTR)
continue;
- int size = mono_counters_size (counter->counter);
- if (size < 0)
- goto cleanup;
-
- if (mono_counters_sample (counter->counter, buffer, size) != size)
+ g_warning ("mono-counters-agent: error with select : %s", strerror(errno));
+ goto cleanup;
+ }
+
+ if (ret == 0) {
+ if (!do_sampling(socketfd))
goto cleanup;
-
- if (!counter->value)
- counter->value = g_malloc (size);
- else if (memcmp (counter->value, buffer, size) == 0)
- continue;
-
- memcpy (counter->value, buffer, size);
-
- if (!write_buffer_to_socket (socketfd, (char*)&counter->index, 2)
- || !write_buffer_to_socket (socketfd, (char*)&size, 2)
- || !write_buffer_to_socket (socketfd, (char*) buffer, size))
+
+ last_sampling = mono_100ns_datetime();
+ } else {
+ if (!read_socket_to_buffer(socketfd, (char*)&cmd, 1))
goto cleanup;
- }
-
- short end = -1;
- if (!write_buffer_to_socket (socketfd, (char*)&end, 2))
- goto cleanup;
- usleep (1000000 / frequency);
+ switch (cmd) {
+ case 0:
+ if (!do_list_counters(socketfd))
+ goto cleanup;
+ break;
+ case 1:
+ if (!do_add_counter(socketfd))
+ goto cleanup;
+ break;
+ case 2:
+ if (!do_remove_counter(socketfd))
+ goto cleanup;
+ break;
+ }
+ }
}
cleanup:
@@ -266,15 +519,15 @@ parse_configuration (const gchar* configuration)
} else if (g_str_has_prefix (opt, "counters=")) {
opt = strchr (opt, '=') + 1;
counters_names = g_strdup(opt);
- } else if (g_str_has_prefix (opt, "frequency=")) {
+ } else if (g_str_has_prefix (opt, "interval=")) {
opt = strchr (opt, '=') + 1;
- frequency = strtol (opt, NULL, 10);
+ interval = strtol (opt, NULL, 10);
}
}
-
+
parse_counters_names(counters_names);
parse_address(address);
-
+
g_free((void*)counters_names);
g_free((void*)address);
g_strfreev(opts);
diff --git a/mono/utils/mono-counters-agent.h b/mono/utils/mono-counters-agent.h
index 1f124b4..b5b4c35 100644
--- a/mono/utils/mono-counters-agent.h
+++ b/mono/utils/mono-counters-agent.h
@@ -3,6 +3,13 @@
#include "mono-compiler.h"
+enum {
+ MONO_COUNTERS_AGENT_STATUS_OK,
+ MONO_COUNTERS_AGENT_STATUS_NOK,
+ MONO_COUNTERS_AGENT_STATUS_NOTFOUND,
+ MONO_COUNTERS_AGENT_STATUS_EXISTING
+};
+
void mono_counters_agent_start (const char *args) MONO_INTERNAL;
#endif /* __MONO_COUNTERS_AGENTS_H__ */
\ No newline at end of file
diff --git a/mono/utils/mono-counters.c b/mono/utils/mono-counters.c
index 0ad160f..b788d08 100644
--- a/mono/utils/mono-counters.c
+++ b/mono/utils/mono-counters.c
@@ -401,7 +401,7 @@ mono_counters_size (MonoCounter* counter)
#if SIZEOF_VOID_P == 8
case MONO_COUNTER_TYPE_WORD:
#endif
- case MONO_COUNTER_DOUBLE:
+ case MONO_COUNTER_TYPE_DOUBLE:
return 8;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment