-
-
Save luhenry/9558842 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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*)×tamp, 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