Skip to content

Instantly share code, notes, and snippets.

@luhenry
Created March 14, 2014 23:01
Show Gist options
  • Save luhenry/9558842 to your computer and use it in GitHub Desktop.
Save luhenry/9558842 to your computer and use it in GitHub Desktop.
diff --cc mono/utils/Makefile.am
index 1a4f6ac,ec2d015..0000000
--- a/mono/utils/Makefile.am
+++ b/mono/utils/Makefile.am
@@@ -69,6 -69,6 +69,7 @@@ monoutils_sources =
monobitset.h \
mono-codeman.h \
mono-counters.h \
++ mono-counters-internals.h \
mono-digest.h \
mono-error.h \
mono-machine.h \
diff --cc mono/utils/mono-counters-internals.h
index a8cbfef,a1d62ce..0000000
--- a/mono/utils/mono-counters-internals.h
+++ b/mono/utils/mono-counters-internals.h
@@@ -1,72 -1,21 +1,94 @@@
#ifndef __MONO_COUNTERS_INTERNALS_H__
#define __MONO_COUNTERS_INTERNALS_H__
-#include <stdio.h>
+ #include <glib.h>
+#include "mono-counters.h"
+#include "mono-compiler.h"
+
+typedef enum {
+ MONO_COUNTER_CAT_JIT,
+ MONO_COUNTER_CAT_GC,
+ MONO_COUNTER_CAT_METADATA,
+ MONO_COUNTER_CAT_GENERICS,
+ MONO_COUNTER_CAT_SECURITY,
+
+ MONO_COUNTER_CAT_REMOTING,
+ MONO_COUNTER_CAT_EXC,
+ MONO_COUNTER_CAT_THREAD,
+ MONO_COUNTER_CAT_THREADPOOL,
+ MONO_COUNTER_CAT_IO,
+} MonoCounterCategory;
+
+typedef enum {
+ MONO_COUNTER_TYPE_INT, /* 4 bytes */
+ MONO_COUNTER_TYPE_LONG, /* 8 bytes */
+ MONO_COUNTER_TYPE_WORD, /* machine word */
+ MONO_COUNTER_TYPE_DOUBLE,
+
+ MONO_COUNTER_TYPE_MAX
+} MonoCounterType;
+
+typedef enum {
+ MONO_COUNTER_UNIT_NONE, /* It's a raw value that needs special handling from the consumer */
+ MONO_COUNTER_UNIT_QUANTITY, /* Quantity of the given counter */
+ MONO_COUNTER_UNIT_TIME, /* This is a timestap in 100n units */
+ MONO_COUNTER_UNIT_EVENT, /* Number of times the given event happens */
+ MONO_COUNTER_UNIT_CONFIG, /* Configuration knob of the runtime */
+} MonoCounterUnit;
+
+typedef enum {
+ MONO_COUNTER_UNIT_CONSTANT = 1, /* This counter doesn't change. Agent will only send it once */
+ MONO_COUNTER_UNIT_MONOTONIC, /* This counter value always increase/decreate over time */
+ MONO_COUNTER_UNIT_VARIABLE, /* This counter value can be anything on each sampling */
+} MonoCounterVariance;
+
+typedef struct _MonoCounter MonoCounter;
+/*
+Limitations:
+ The old-style string counter type won't work as they cannot be safely sampled during execution.
+
+TODO:
+ Size-bounded String counter.
+ Sampler function that take user data arguments (could we use them for user perf counters?)
+ Dynamic category registration.
+ MonoCounter size diet once we're done with the above.
+*/
+void*
+mono_counters_new (MonoCounterCategory category, const char *name, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance) MONO_INTERNAL;
+
+MonoCounter*
+mono_counters_register_full (MonoCounterCategory category, const char *name, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance, void *addr) MONO_INTERNAL;
+
+#define mono_counters_new_int(cat,name,unit,variance) mono_counters_new(cat,name,MONO_COUNTER_TYPE_INT,unit,variance)
+#define mono_counters_new_word(cat,name,unit,variance) mono_counters_new(cat,name,MONO_COUNTER_TYPE_WORD,unit,variance)
+#define mono_counters_new_long(cat,name,unit,variance) mono_counters_new(cat,name,MONO_COUNTER_TYPE_LONG,unit,variance)
+#define mono_counters_new_double(cat,name,unit,variance) mono_counters_new(cat,name,MONO_COUNTER_TYPE_double,unit,variance)
+
+#define mono_counters_new_int_const(cat,name,unit,value) do { int *__ptr = mono_counters_new(cat,name,MONO_COUNTER_TYPE_INT,unit,variance); *__ptr = value; } while (0)
+#define mono_counters_new_word_const(cat,name,unit,value) do { ssize_t *__ptr = mono_counters_new(cat,name,MONO_COUNTER_TYPE_INT,unit,variance); *__ptr = value; } while (0)
+#define mono_counters_new_long_const(cat,name,unit,value) do { gint64 *__ptr = mono_counters_new(cat,name,MONO_COUNTER_TYPE_INT,unit,variance); *__ptr = value; } while (0)
+#define mono_counters_new_double_const(cat,name,unit,value) do { double *__ptr = mono_counters_new(cat,name,MONO_COUNTER_TYPE_INT,unit,variance); *__ptr = value; } while (0)
+ MONO_API void mono_counters_dump_on_cleanup (void);
+ MONO_API int mono_counters_dump_on_cleanup_enable (void);
-MONO_API int mono_counters_get_by_category_and_name (const char* category, const char* name, void** addr, int* type);
++MONO_API int mono_counters_get (MonoCounterCategory category, const char* name, void** addr, MonoCounterType* type, MonoCounterUnit *unit, MonoCounterVariance *variance, gboolean* is_callback);
++
++MONO_API MonoCounterCategory mono_counters_category_name_to_id (const char* name);
++MONO_API const char* mono_counters_category_id_to_name (MonoCounterCategory id);
++
++typedef int (*MonoCountersForeachFunc) (MonoCounterCategory category, const char* name, void* addr, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance, gboolean is_callback, void** args);
++MONO_API void mono_counters_foreach(MonoCountersForeachFunc func, void** args);
++
++MONO_API int mono_counters_get_int (void* addr, gboolean is_callback);
++#if SIZEOF_VOID_P == 4
++MONO_API int mono_counters_get_word (void* addr, gboolean is_callback);
++#elif SIZEOF_VOID_P == 8
++MONO_API gint64 mono_counters_get_word (void* addr, gboolean is_callback);
+#endif
++MONO_API gint64 mono_counters_get_long (void* addr, gboolean is_callback);
++MONO_API double mono_counters_get_double (void* addr, gboolean is_callback);
+
-MONO_API int mono_counters_get_int (int type, void* addr);
-MONO_API guint mono_counters_get_uint (int type, void* addr);
-MONO_API gint64 mono_counters_get_long (int type, void* addr);
-MONO_API guint64 mono_counters_get_ulong (int type, void* addr);
-MONO_API gssize mono_counters_get_word (int type, void* addr);
-MONO_API double mono_counters_get_double (int type, void* addr);
-MONO_API char* mono_counters_get_string (int type, void* addr);
+
+ #endif /* __MONO_COUNTERS_INTERNALS_H__ */
+
diff --cc mono/utils/mono-counters.c
index 9f22e01,15a92bd..0000000
--- a/mono/utils/mono-counters.c
+++ b/mono/utils/mono-counters.c
@@@ -20,7 -19,10 +23,9 @@@ struct _MonoCounter
static MonoCounter *counters = NULL;
static int valid_mask = 0;
-static int set_mask = 0;
+ static int dump_on_cleanup = 0;
+
/**
* mono_counters_enable:
* @section_mask: a mask listing the sections that will be displayed
@@@ -33,77 -35,18 +38,89 @@@ mono_counters_enable (int section_mask
valid_mask = section_mask & MONO_COUNTER_SECTION_MASK;
}
+MonoCounter*
+mono_counters_register_full (MonoCounterCategory category, const char *name, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance, void *addr)
+{
+ MonoCounter *counter;
+ counter = malloc (sizeof (MonoCounter));
+ if (!counter)
+ return NULL;
+ counter->name = name;
+ counter->addr = addr;
+ counter->type = type;
+ counter->category = category;
+ counter->unit = unit;
+ counter->variance = variance;
+ counter->next = NULL;
+
+ /* Append */
+ if (counters) {
+ MonoCounter *item = counters;
+ while (item->next)
+ item = item->next;
+ item->next = counter;
+ } else {
+ counters = counter;
+ }
+ return counter;
+}
+
+static void*
+mono_counters_alloc_space (int size)
+{
+ //FIXME actually alloc memory from perf-counters
+ return g_malloc (size);
+}
+
+void*
+mono_counters_new (MonoCounterCategory category, const char *name, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance)
+{
+ const int sizes[] = { 4, 8, sizeof (void*) };
+ void *addr;
+
+ g_assert (type >= MONO_COUNTER_TYPE_INT && type < MONO_COUNTER_TYPE_MAX);
+
+ addr = mono_counters_alloc_space (sizes [type]);
+ if (!addr)
+ return NULL;
+ if (!mono_counters_register_full (category, name, type, unit, variance, addr))
+ return NULL; //FIXME release the counter memory?
+
+ return addr;
+}
+
+
+static int
+section_to_category (int type)
+{
+ switch (type & MONO_COUNTER_SECTION_MASK) {
+ case MONO_COUNTER_JIT:
+ return MONO_COUNTER_CAT_JIT;
+ case MONO_COUNTER_GC:
+ return MONO_COUNTER_CAT_GC;
+ case MONO_COUNTER_METADATA:
+ return MONO_COUNTER_CAT_METADATA;
+ case MONO_COUNTER_GENERICS:
+ return MONO_COUNTER_CAT_GENERICS;
+ case MONO_COUNTER_SECURITY:
+ return MONO_COUNTER_CAT_SECURITY;
+ default:
+ g_error ("Invalid section %x", type & MONO_COUNTER_SECTION_MASK);
+ }
+}
+
+ void
+ mono_counters_dump_on_cleanup (void)
+ {
+ dump_on_cleanup = 1;
+ }
+
+ int
+ mono_counters_dump_on_cleanup_enable (void)
+ {
+ return dump_on_cleanup;
+ }
+
/**
* mono_counters_register:
* @name: The name for this counters.
@@@ -117,45 -60,33 +134,47 @@@
* It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
* the function should return the value and take no arguments.
*/
-void
+void
mono_counters_register (const char* name, int type, void *addr)
{
+ MonoCounterCategory cat = section_to_category (type);
+ MonoCounterType counter_type;
+ MonoCounterUnit unit = MONO_COUNTER_UNIT_NONE;
MonoCounter *counter;
- if (!(type & valid_mask))
- return;
- counter = malloc (sizeof (MonoCounter));
- if (!counter)
- return;
- counter->name = name;
- counter->type = type;
- counter->addr = addr;
- counter->next = NULL;
-
- set_mask |= type;
- /* Append */
- if (counters) {
- MonoCounter *item = counters;
- while (item->next)
- item = item->next;
- item->next = counter;
- } else {
- counters = counter;
+ switch (type & MONO_COUNTER_TYPE_MASK) {
+ case MONO_COUNTER_INT:
+ case MONO_COUNTER_UINT:
+ counter_type = MONO_COUNTER_TYPE_INT;
+ break;
+ case MONO_COUNTER_LONG:
+ case MONO_COUNTER_ULONG:
+ counter_type = MONO_COUNTER_TYPE_LONG;
+ break;
+ case MONO_COUNTER_DOUBLE:
+ counter_type = MONO_COUNTER_TYPE_DOUBLE;
+ break;
+ case MONO_COUNTER_WORD:
+ counter_type = MONO_COUNTER_TYPE_WORD;
+ break;
+ case MONO_COUNTER_STRING:
+ g_error ("String counters no longer work");
+ case MONO_COUNTER_TIME_INTERVAL:
+ counter_type = MONO_COUNTER_TYPE_LONG;
+ unit = MONO_COUNTER_UNIT_TIME;
+ break;
+ default:
+ g_error ("Invalid type %x", type & MONO_COUNTER_TYPE_MASK);
}
+
+ counter = mono_counters_register_full (cat, name, counter_type, unit, MONO_COUNTER_UNIT_VARIABLE, addr);
+ if (counter && type & MONO_COUNTER_CALLBACK)
+ counter->is_callback = TRUE;
++ else
++ counter->is_callback = FALSE;
}
+
typedef int (*IntFunc) (void);
typedef guint (*UIntFunc) (void);
typedef gint64 (*LongFunc) (void);
@@@ -334,4 -298,80 +356,127 @@@ mono_runtime_resource_set_callback (Mon
limit_reached = callback;
}
+ int
-mono_counters_get_by_category_and_name (const char* category, const char* name, void** addr, int* type)
++mono_counters_get (MonoCounterCategory category, const char* name, void** addr, MonoCounterType* type, MonoCounterUnit *unit, MonoCounterVariance *variance, gboolean* is_callback)
+ {
+ if (!counters)
+ return 0;
-
- int t;
-
- if (strcmp(category, "Mono JIT")) {
- t = MONO_COUNTER_JIT;
- } else if (strcmp(category, "Mono GC")) {
- t = MONO_COUNTER_GC;
- } else if (strcmp(category, "Mono Generics")) {
- t = MONO_COUNTER_GENERICS;
- } else if (strcmp(category, "Mono Metadata")) {
- t = MONO_COUNTER_METADATA;
- } else if (strcmp(category, "Mono Security")) {
- t = MONO_COUNTER_SECURITY;
- } else {
- t = 0x7FFFFFFF;
- }
+
+ MonoCounter* counter = counters;
+
+ do {
- if ((counter->type & t) && strcmp(counter->name, name)) {
- *type = counter->type;
++ if (counter->category == category && strcmp(counter->name, name) == 0) {
+ *addr = counter->addr;
++ *type = counter->type;
++ *unit = counter->unit;
++ *variance = counter->variance;
++ *is_callback = counter->is_callback;
+ return 1;
+ }
+ } while ((counter = counter->next));
-
++
+ return 0;
+ }
+
-int
-mono_counters_get_int (int type, void* addr)
++MonoCounterCategory
++mono_counters_category_name_to_id (const char* name)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((IntFunc)addr) () : *(int*)addr;
++ if (strcmp("Mono JIT", name) == 0) {
++ return MONO_COUNTER_CAT_JIT;
++ } else if (strcmp("Mono GC", name) == 0) {
++ return MONO_COUNTER_CAT_GC;
++ } else if (strcmp("Mono Metadata", name) == 0) {
++ return MONO_COUNTER_CAT_METADATA;
++ } else if (strcmp("Mono Generics", name) == 0) {
++ return MONO_COUNTER_CAT_GENERICS;
++ } else if (strcmp("Mono Security", name) == 0) {
++ return MONO_COUNTER_CAT_SECURITY;
++ } else if (strcmp("Mono Remoting", name) == 0) {
++ return MONO_COUNTER_CAT_REMOTING;
++ } else if (strcmp("Mono EXC", name) == 0) {
++ return MONO_COUNTER_CAT_EXC;
++ } else if (strcmp("Mono Thread", name) == 0) {
++ return MONO_COUNTER_CAT_THREAD;
++ } else if (strcmp("Mono Threadpool", name) == 0) {
++ return MONO_COUNTER_CAT_THREADPOOL;
++ } else if (strcmp("Mono IO", name) == 0) {
++ return MONO_COUNTER_CAT_IO;
++ } else {
++ return -1;
++ }
+ }
+
-guint
-mono_counters_get_uint (int type, void* addr)
++const char*
++mono_counters_category_id_to_name (MonoCounterCategory id)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((UIntFunc)addr) () : *(guint*)addr;
++ switch (id) {
++ case MONO_COUNTER_CAT_JIT:
++ return "Mono JIT";
++ case MONO_COUNTER_CAT_GC:
++ return "Mono GC";
++ case MONO_COUNTER_CAT_METADATA:
++ return "Mono Metadata";
++ case MONO_COUNTER_CAT_GENERICS:
++ return "Mono Generics";
++ case MONO_COUNTER_CAT_SECURITY:
++ return "Mono Security";
++ case MONO_COUNTER_CAT_REMOTING:
++ return "Mono Remoting";
++ case MONO_COUNTER_CAT_EXC:
++ return "Mono EXC";
++ case MONO_COUNTER_CAT_THREAD:
++ return "Mono Thread";
++ case MONO_COUNTER_CAT_THREADPOOL:
++ return "Mono Threadpool";
++ case MONO_COUNTER_CAT_IO:
++ return "Mono IO";
++ default:
++ return NULL;
++ }
+ }
+
-gint64
-mono_counters_get_long (int type, void* addr)
++int
++mono_counters_get_int (void* addr, gboolean is_callback)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((LongFunc)addr) () : *(gint64*)addr;
++ return is_callback ? ((IntFunc)addr) () : *(int*)addr;
+ }
+
-guint64
-mono_counters_get_ulong (int type, void* addr)
++gint64
++mono_counters_get_long (void* addr, gboolean is_callback)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((ULongFunc)addr) () : *(guint64*)addr;
++ return is_callback ? ((LongFunc)addr) () : *(gint64*)addr;
+ }
-
-gssize
-mono_counters_get_word (int type, void* addr)
++#if SIZEOF_VOID_P == 4
++int
++mono_counters_get_word (void* addr, gboolean is_callback)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((PtrFunc)addr) () : *(gssize*)addr;
++ return mono_counters_get_int(addr, is_callback);
+ }
++#elif SIZEOF_VOID_P == 8
++gint64
++mono_counters_get_word (void* addr, gboolean is_callback)
++{
++ return mono_counters_get_long(addr, is_callback);
++}
++#endif
+
+ double
-mono_counters_get_double (int type, void* addr)
++mono_counters_get_double (void* addr, gboolean is_callback)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((DoubleFunc)addr) () : *(double*)addr;
++ return is_callback ? ((DoubleFunc)addr) () : *(double*)addr;
+ }
+
-char*
-mono_counters_get_string (int type, void* addr)
++void
++mono_counters_foreach(MonoCountersForeachFunc func, void** args)
+ {
- return (type & MONO_COUNTER_CALLBACK) ? ((StrFunc)addr) () : *(char**)addr;
++ if (!counters)
++ return;
++
++ MonoCounter* counter = counters;
++
++ do {
++ if (!func(counter->category, counter->name, counter->addr, counter->type, counter->unit, counter->variance, counter->is_callback, args))
++ return;
++ } while ((counter = counter->next));
+ }
diff --git a/mono/utils/mono-counters-agent.c b/mono/utils/mono-counters-agent.c
index 84a562c..c5a3f79 100644
--- a/mono/utils/mono-counters-agent.c
+++ b/mono/utils/mono-counters-agent.c
@@ -4,121 +4,239 @@
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include <pthread.h>
#include <glib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include "mono-counters.h"
#include "mono-counters-internals.h"
#include "mono-counters-agent.h"
+#include "mono-time.h"
-typedef struct MonoCounter {
- const char* name;
- const char* category;
- int type;
- void* value;
-} MonoCounter;
+/**
+ * Protocol :
+ * | Headers | Values | Values | ... [Infinity]
+ *
+ * Headers :
+ * | Count (2) | Counter | Counter | ... [Count]
+ *
+ * Counter :
+ * | Category (4) | Name Length (8) | Name (Name Length) | Type (4) | Unit (4) | Variance (4) | Index (2) |
+ *
+ * Values :
+ * | Timestamp (8) | Value | Value | ... | -1 (2) |
+ *
+ * Value :
+ * | Index (2) | Size (2) | Value (Size) |
+ */
-static GSList* counters;
+typedef struct MonoCounterAgent {
+ MonoCounterCategory category;
+ const char* name;
+ void* addr;
+ MonoCounterType type;
+ MonoCounterUnit unit;
+ MonoCounterVariance variance;
+ gboolean is_callback;
+ // MonoCounterAgent specific data :
+ void* value;
+ short index;
+} MonoCounterAgent;
-static int frequency;
-static gchar* inspector_ip;
-static int inspector_port;
+static pthread_t agent_thread;
-static unsigned int buffer_size;
-static void* buffer;
+static GSList* counters;
-static pthread_t agent_thread;
+static const gchar* inspector_ip;
+static int inspector_port;
+static int frequency;
static int enable;
+static const short size4 = 4;
+static const short size8 = 8;
+
void
mono_counters_agent_enable (void)
{
enable = 1;
}
-void
-parse_counter_names (const char *counters_names)
+int
+parse_counters_all (MonoCounterCategory category, const char* name, void* addr, MonoCounterType type, MonoCounterUnit unit, MonoCounterVariance variance, gboolean is_callback, void** args)
{
- if (counters_names == NULL) {
- // FIXME iterate over all counters
- }
+ static short index = 0;
- gchar **names = g_strsplit (counters_names, ";", -1), **ptr;
+ MonoCounterAgent* counter = g_malloc(sizeof(MonoCounterAgent));
+ counter->category = category;
+ counter->name = g_strdup(name);
+ counter->addr = addr;
+ counter->type = type;
+ counter->unit = unit;
+ counter->variance = variance;
+ counter->is_callback = is_callback;
+ counter->value = NULL;
+ counter->index = index;
- for (ptr = names; *ptr; ++ptr) {
- gchar **split = g_strsplit(*ptr, "/", 2);
- if (!split[0] || !split[1])
- continue; //FIXME warning
-
- void* addr;
- int type;
+ counters = g_slist_append (counters, counter);
+ index += 1;
+
+ return 1;
+}
+
+void
+parse_counters_names (const char *counters_names)
+{
+ if (!counters_names) {
+ mono_counters_foreach(parse_counters_all, NULL);
+ } else {
+ short index = 0;
+ gchar **names = g_strsplit (counters_names, ";", -1), **ptr;
+
+ for (ptr = names; *ptr; ++ptr) {
+ gchar **split = g_strsplit(*ptr, "/", 2);
+ if (!split[0] || !split[1])
+ continue; //FIXME warning
- if (!mono_counters_get_by_category_and_name(split[0], split[1], &addr, &type)) {
- continue; // FIXME warning
- }
+ MonoCounterCategory category = mono_counters_category_name_to_id(split[0]);
+
+ void* addr;
+ MonoCounterType type;
+ MonoCounterUnit unit;
+ MonoCounterVariance variance;
+ gboolean is_callback;
- MonoCounter* counter = g_malloc(sizeof(MonoCounter));
- counter->category = split[0];
- counter->name = split[1];
- counter->value = addr;
- counter->type = type;
+ if (!mono_counters_get(category, split[1], &addr, &type, &unit, &variance, &is_callback)) {
+ continue; // FIXME warning
+ }
- switch (counter->type & MONO_COUNTER_TYPE_MASK) {
- case MONO_COUNTER_INT:
- case MONO_COUNTER_UINT:
- buffer_size += 6;
- break;
- case MONO_COUNTER_LONG:
- case MONO_COUNTER_ULONG:
- case MONO_COUNTER_WORD:
- case MONO_COUNTER_DOUBLE:
- case MONO_COUNTER_STRING:
- case MONO_COUNTER_TIME_INTERVAL:
- buffer_size += 8;
- break;
- }
+ MonoCounterAgent* counter = g_malloc(sizeof(MonoCounterAgent));
+ counter->category = category;
+ counter->name = g_strdup(split[1]);
+ counter->addr = addr;
+ counter->type = type;
+ counter->unit = unit;
+ counter->variance = variance;
+ counter->is_callback = is_callback;
+ counter->index = index;
+ counter->value = NULL;
- counters = g_slist_append (counters, counter);
+ counters = g_slist_append (counters, counter);
+ index += 1;
- g_strfreev(split);
+ g_strfreev(split);
+ }
+ g_strfreev (names);
}
- g_strfreev (names);
}
void
parse_address (const char *address)
{
- gchar **split = g_strsplit(address, ":", 2);
+ if (!address) {
+ inspector_ip = "127.0.0.1";
+ inspector_port = 8888;
+ } else {
+ gchar **split = g_strsplit(address, ":", 2);
- inspector_ip = (split[0]) ? g_strdup(split[0]) : "127.0.0.1"; // FIXME error
- inspector_port = (split[1]) ? strtol(split[1], NULL, 10) : 8888;
+ inspector_ip = (split[0]) ? g_strdup(split[0]) : "127.0.0.1"; // FIXME error
+ inspector_port = (split[1]) ? strtol(split[1], NULL, 10) : 8888;
- g_strfreev(split);
+ g_strfreev(split);
+ }
}
-void
-write_counter_to_buffer (short type, void* name, size_t name_size, void* value, size_t value_size, int* offset)
+int
+write_buffer_to_socket(int socketfd, char* buffer, ssize_t size)
{
- memcpy(&type, &buffer[*offset], 2); *offset += 2;
- memcpy(name, &buffer[*offset], name_size); *offset += name_size;
- memcpy(value, &buffer[*offset], value_size); *offset += value_size;
+ ssize_t left = size, sent;
+
+ while (left > 0) {
+ sent = send(socketfd, buffer + (size - left), left, 0);
+ if (sent <= 0)
+ return 0;
+ left -= sent;
+ }
+
+ return 1;
+}
+
+int
+mono_counters_agent_write_int (MonoCounterAgent* counter, int socketfd)
+{
+ int value = mono_counters_get_int (counter->addr, counter->is_callback);
+
+ if (!counter->value)
+ counter->value = g_malloc(4);
+ else if (*(int*)counter->value == value)
+ return 1;
+
+ *(int*)counter->value = value;
+
+ if (!write_buffer_to_socket(socketfd, (char*)&counter->index, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&size4, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&value, 4))
+ return 0;
+
+ return 1;
+}
+
+int
+mono_counters_agent_write_long (MonoCounterAgent* counter, int socketfd)
+{
+ gint64 value = mono_counters_get_long (counter->addr, counter->is_callback);
+
+ if (!counter->value)
+ counter->value = g_malloc(8);
+ else if (*(gint64*)counter->value == value)
+ return 1;
+
+ *(gint64*)counter->value = value;
+
+ if (!write_buffer_to_socket(socketfd, (char*)&counter->index, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&size8, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&value, 8))
+ return 0;
+
+ return 1;
+}
+
+int
+mono_counters_agent_write_double (MonoCounterAgent* counter, int socketfd)
+{
+ double value = mono_counters_get_double (counter->addr, counter->is_callback);
+
+ if (!counter->value)
+ counter->value = g_malloc(8);
+ else if (*(double*)counter->value == value)
+ return 1;
+
+ *(double*)counter->value = value;
+
+ if (!write_buffer_to_socket(socketfd, (char*)&counter->index, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&size8, 2)
+ || !write_buffer_to_socket(socketfd, (char*)&value, 8))
+ return 0;
+
+ return 1;
}
static void*
mono_counters_agent_sampling_thread (void* ptr)
{
+ GSList* item;
+
int socketfd = 0;
struct sockaddr_in inspector_addr;
- struct timeval tv;
if ((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- g_printf("mono-counters-agent : error with socket");
+ g_printf("mono-counters-agent | error with socket : %s", strerror(errno));
return NULL;
}
@@ -127,81 +245,82 @@ mono_counters_agent_sampling_thread (void* ptr)
inspector_addr.sin_family = AF_INET;
inspector_addr.sin_port = htons(inspector_port);
- if (inet_pton(AF_INET, inspector_ip, &inspector_addr.sin_addr) < 0) {
- g_printf("mono-counters-agent : error with inet_pton");
+ if (!inet_pton(AF_INET, inspector_ip, &inspector_addr.sin_addr)) {
+ g_printf("mono-counters-agent | error with inet_pton : %s", strerror(errno));
return NULL;
}
if (connect(socketfd, (struct sockaddr*)&inspector_addr, sizeof(inspector_addr)) < 0) {
- g_printf("mono-counters-agent : error with connect");
+ g_printf("mono-counters-agent | error with connect : %s", strerror(errno));
return NULL;
}
- while (1) {
- sleep (1000 / frequency);
+ short count = 0;
+ for (item = counters; item; item = item->next)
+ count += 1;
- int offset = 0;
-
- gettimeofday(&tv, NULL);
- memcpy(&tv.tv_sec, &buffer[0], 8); offset += 8;
- memcpy(&tv.tv_usec, &buffer[8], 8); offset += 8;
+ if (!write_buffer_to_socket(socketfd, (char*)&count, 2))
+ goto error;
+
+ for (item = counters; item; item = item->next) {
+ MonoCounterAgent* counter = item->data;
- GSList* item = counters;
+ int len = strlen(counter->name);
- while (item != NULL) {
- MonoCounter* counter = item->data;
+ if (!write_buffer_to_socket(socketfd, (char*)&counter->category, 4)
+ || !write_buffer_to_socket(socketfd, (char*)&len, 4)
+ || !write_buffer_to_socket(socketfd, (char*) counter->name, len)
+ || !write_buffer_to_socket(socketfd, (char*)&counter->type, 4)
+ || !write_buffer_to_socket(socketfd, (char*)&counter->unit, 4)
+ || !write_buffer_to_socket(socketfd, (char*)&counter->variance, 4)
+ || !write_buffer_to_socket(socketfd, (char*)&counter->index, 2))
+ goto error; // FIXME error
+ }
+
+ while (1) {
+ gint64 timestamp = mono_100ns_ticks();
+ if (!write_buffer_to_socket(socketfd, (char*)&timestamp, 8))
+ goto error; // FIXME error
+
+ for (item = counters; item; item = item->next) {
+ MonoCounterAgent* counter = item->data;
if (!counter)
continue; // FIXME warning
-
- int intval;
- guint uintval;
- gint64 int64val;
- guint64 uint64val;
- gssize wordval;
- double doubleval;
-
- switch (counter->type & MONO_COUNTER_TYPE_MASK) {
- case MONO_COUNTER_INT:
- intval = mono_counters_get_int (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &intval, 4, &offset);
- break;
- case MONO_COUNTER_UINT:
- uintval = mono_counters_get_uint (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &uintval, 4, &offset);
- break;
- case MONO_COUNTER_LONG:
- int64val = mono_counters_get_long (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &int64val, 8, &offset);
- break;
- case MONO_COUNTER_ULONG:
- uint64val = mono_counters_get_ulong (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &uint64val, 8, &offset);
+
+ switch (counter->type) {
+ case MONO_COUNTER_TYPE_INT:
+#if SIZEOF_VOID_P == 4
+ case MONO_COUNTER_TYPE_WORD:
+#endif
+ if (!mono_counters_agent_write_int(counter, socketfd))
+ goto error;
break;
- case MONO_COUNTER_WORD:
- wordval = mono_counters_get_word (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &wordval, 8, &offset);
+ case MONO_COUNTER_TYPE_LONG:
+#if SIZEOF_VOID_P == 8
+ case MONO_COUNTER_TYPE_WORD:
+#endif
+ if (!mono_counters_agent_write_long(counter, socketfd))
+ goto error;
break;
case MONO_COUNTER_DOUBLE:
- doubleval = mono_counters_get_ulong (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &doubleval, 8, &offset);
- break;
- case MONO_COUNTER_STRING:
- // FIXME
- break;
- case MONO_COUNTER_TIME_INTERVAL:
- int64val = mono_counters_get_long (counter->type, counter->value);
- write_counter_to_buffer(0, 0, 4, &int64val, 8, &offset);
+ if (!mono_counters_agent_write_double(counter, socketfd))
+ goto error;
break;
}
-
- item = item->next;
}
+
+ short end = -1;
+ if (!write_buffer_to_socket(socketfd, (char*)&end, 2))
+ goto error; // FIXME error
- write(socketfd, buffer, offset);
+ usleep (1000000 / frequency);
}
+
+error:
+ close(socketfd);
- g_free(buffer);
+ return NULL;
}
void
@@ -212,7 +331,7 @@ mono_counters_agent_start (void)
const gchar *env = g_getenv ("MONO_PERF_AGENT");
- const char *counters_names;
+ const char *counters_names = NULL;
const char *address;
if (env == NULL)
@@ -233,17 +352,12 @@ mono_counters_agent_start (void)
}
}
- // Minimal size for timestamp
- buffer_size = 16;
-
- parse_counter_names(counters_names);
+ parse_counters_names(counters_names);
parse_address(address);
g_free((void*)counters_names);
g_free((void*)address);
g_strfreev(opts);
- buffer = g_malloc(buffer_size);
-
pthread_create(&agent_thread, NULL, mono_counters_agent_sampling_thread, NULL);
}
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment