#include <stdlib.h>
#include <glib.h>
+#include "config.h"
#include "mono-counters.h"
+#include "mono-proclib.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
struct _MonoCounter {
MonoCounter *next;
static int valid_mask = 0;
static int set_mask = 0;
+/**
+ * mono_counter_get_variance:
+ * @counter: counter to get the variance
+ *
+ * Variance specifies how the counter value is expected to behave between any two samplings.
+ *
+ * Returns: the monotonicity of the counter.
+ */
int
mono_counter_get_variance (MonoCounter *counter)
{
return counter->type & MONO_COUNTER_VARIANCE_MASK;
}
+/**
+ * mono_counter_get_unit:
+ * @counter: counter to get the unit
+ *
+ * The unit gives a high level view of the unit that the counter is measuring.
+ *
+ * Returns: the unit of the counter.
+ */
int
mono_counter_get_unit (MonoCounter *counter)
{
return counter->type & MONO_COUNTER_UNIT_MASK;
}
+/**
+ * mono_counter_get_section:
+ * @counter: counter to get the section
+ *
+ * Sections are the unit of organization between all counters.
+ *
+ * Returns: the section of the counter.
+ */
+
int
mono_counter_get_section (MonoCounter *counter)
{
return counter->type & MONO_COUNTER_SECTION_MASK;
}
+/**
+ * mono_counter_get_type:
+ * @counter: counter to get the type
+ *
+ * Returns the type used to strong the value of the counter.
+ *
+ * Returns:the type of the counter.
+ */
int
mono_counter_get_type (MonoCounter *counter)
{
return counter->type & MONO_COUNTER_TYPE_MASK;
}
+/**
+ * mono_counter_get_name:
+ * @counter: counter to get the name
+ *
+ * Returns the counter name. The string should not be freed.
+ *
+ * Returns the name of the counter.
+ */
+
const char*
mono_counter_get_name (MonoCounter *counter)
{
return counter->name;
}
+/**
+ * mono_counter_get_size:
+ * @counter: counter to get the max size of the counter
+ *
+ * Use the returned size to create the buffer used with mono_counters_sample
+ *
+ * Returns: the max size of the counter data.
+ */
size_t
mono_counter_get_size (MonoCounter *counter)
{
* Note that @name must be a valid string at all times until
* mono_counters_dump () is called.
*
+ * This function should not be used with counter types that require an explicit size such as string
+ * as the counter size will be set to zero making them effectively useless.
+ *
+ *
* It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
* the function should return the value and take no arguments.
*/
* @name: The name for this counters.
* @type: One of the possible MONO_COUNTER types, or MONO_COUNTER_CALLBACK for a function pointer.
* @addr: The address to register.
- * @size: The memory size of the address, default to 0 for MONO_COUNTER_STRING type.
+ * @size: Max size of the counter data.
*
* Register addr as the address of a counter of type @type.
* Note that @name must be a valid string at all times until
* It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
* the function should return the value and take no arguments.
*
- * Use @size for type that can have dynamic size such as string.
+ * The value of @size is ignored for types with fixed size such as int and long.
+ *
+ * Use @size for types that can have dynamic size such as string.
+ *
+ * If @size is negative, it's silently converted to zero.
*/
void
mono_counters_register_with_size (const char *name, int type, void *addr, int size)
if ((type & MONO_COUNTER_VARIANCE_MASK) == 0)
type |= MONO_COUNTER_MONOTONIC;
+ if (size < 0)
+ size = 0;
counter = malloc (sizeof (MonoCounter));
if (!counter)
#define ENTRY_FMT "%-36s: "
static void
dump_counter (MonoCounter *counter, FILE *outfile) {
- int intval;
- guint uintval;
- gint64 int64val;
- guint64 uint64val;
- gssize wordval;
- double dval;
- const char *str;
+ void *buffer = g_malloc0 (counter->size);
+ mono_counters_sample (counter, buffer, counter->size);
+
switch (counter->type & MONO_COUNTER_TYPE_MASK) {
case MONO_COUNTER_INT:
- if (counter->type & MONO_COUNTER_CALLBACK)
- intval = ((IntFunc)counter->addr) ();
- else
- intval = *(int*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%d\n", counter->name, intval);
- break;
+ fprintf (outfile, ENTRY_FMT "%d\n", counter->name, *(int*)buffer);
+ break;
case MONO_COUNTER_UINT:
- if (counter->type & MONO_COUNTER_CALLBACK)
- uintval = ((UIntFunc)counter->addr) ();
- else
- uintval = *(guint*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%u\n", counter->name, uintval);
- break;
+ fprintf (outfile, ENTRY_FMT "%u\n", counter->name, *(guint*)buffer);
+ break;
case MONO_COUNTER_LONG:
- if (counter->type & MONO_COUNTER_CALLBACK)
- int64val = ((LongFunc)counter->addr) ();
- else
- int64val = *(gint64*)counter->addr;
- if (mono_counter_get_unit (counter) == MONO_COUNTER_TIME)
- fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 10000.0);
- else
- fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (long long)int64val);
- break;
+ if ((counter->type & MONO_COUNTER_UNIT_MASK) == MONO_COUNTER_TIME)
+ fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 10000.0);
+ else
+ fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, *(gint64*)buffer);
+ break;
case MONO_COUNTER_ULONG:
- if (counter->type & MONO_COUNTER_CALLBACK)
- uint64val = ((ULongFunc)counter->addr) ();
- else
- uint64val = *(guint64*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
- break;
+ fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, *(guint64*)buffer);
+ break;
case MONO_COUNTER_WORD:
- if (counter->type & MONO_COUNTER_CALLBACK)
- wordval = ((PtrFunc)counter->addr) ();
- else
- wordval = *(gssize*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, (gint64)wordval);
- break;
+ fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, *(gssize*)buffer);
+ break;
case MONO_COUNTER_DOUBLE:
- if (counter->type & MONO_COUNTER_CALLBACK)
- dval = ((DoubleFunc)counter->addr) ();
- else
- dval = *(double*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
- break;
+ fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, *(double*)buffer);
+ break;
case MONO_COUNTER_STRING:
- if (counter->type & MONO_COUNTER_CALLBACK)
- str = ((StrFunc)counter->addr) ();
- else
- str = (char*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%s\n", counter->name, str);
- break;
+ fprintf (outfile, ENTRY_FMT "%s\n", counter->name, (counter->size == 0) ? "(null)" : (char*)buffer);
+ break;
case MONO_COUNTER_TIME_INTERVAL:
- if (counter->type & MONO_COUNTER_CALLBACK)
- int64val = ((LongFunc)counter->addr) ();
- else
- int64val = *(gint64*)counter->addr;
- fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)int64val / 1000.0);
+ fprintf (outfile, ENTRY_FMT "%.2f ms\n", counter->name, (double)(*(gint64*)buffer) / 1000.0);
break;
}
+
+ g_free (buffer);
}
+static gint64
+user_time (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_USER_TIME);
+}
+
+static gint64
+system_time (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_SYSTEM_TIME);
+}
+
+static gint64
+total_time (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_TOTAL_TIME);
+}
+
+static gint64
+working_set (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_WORKING_SET);
+}
+
+static gint64
+private_bytes (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_PRIVATE_BYTES);
+}
+
+static gint64
+virtual_bytes (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_VIRTUAL_BYTES);
+}
+
+static gint64
+page_faults (void)
+{
+ return mono_process_get_data (GINT_TO_POINTER (mono_process_current_pid ()), MONO_PROCESS_FAULTS);
+}
+
+static double
+cpu_load (int kind)
+{
+#if defined(TARGET_WIN32)
+#elif defined(TARGET_MACH)
+ double load [3];
+ if (getloadavg (load, 3) > 0)
+ return load [kind];
+#else
+ char buffer[512], *b;
+ int len, i;
+ FILE *f = fopen ("/proc/loadavg", "r");
+ if (f) {
+ len = fread (buffer, 1, sizeof (buffer) - 1, f);
+ if (len > 0) {
+ buffer [len < 511 ? len : 511] = 0;
+ b = buffer;
+ for (i = 0; i < 3; i++) {
+ if (kind == i)
+ return strtod (b, NULL);
+ if (i < 2) {
+ b = strchr (b, ' ');
+ if (!b)
+ return 0;
+ b += 1;
+ }
+ }
+ }
+ fclose (f);
+ }
+#endif
+ return 0;
+}
+
+static double
+cpu_load_1min (void)
+{
+ return cpu_load (0);
+}
+
+static double
+cpu_load_5min (void)
+{
+ return cpu_load (1);
+}
+
+static double
+cpu_load_15min (void)
+{
+ return cpu_load (2);
+}
+
+static gboolean system_counters_initialized = FALSE;
+
+#define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
+#define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
+#define SYSCOUNTER_COUNT (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_COUNT | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK)
+#define SYSCOUNTER_LOAD (MONO_COUNTER_SYSTEM | MONO_COUNTER_DOUBLE | MONO_COUNTER_PERCENTAGE | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK)
+
+static void
+initialize_system_counters (void)
+{
+ mono_counters_register ("User Time", SYSCOUNTER_TIME, &user_time);
+ mono_counters_register ("System Time", SYSCOUNTER_TIME, &system_time);
+ mono_counters_register ("Total Time", SYSCOUNTER_TIME, &total_time);
+ mono_counters_register ("Working Set", SYSCOUNTER_BYTES, &working_set);
+ mono_counters_register ("Private Bytes", SYSCOUNTER_BYTES, &private_bytes);
+ mono_counters_register ("Virtual Bytes", SYSCOUNTER_BYTES, &virtual_bytes);
+ mono_counters_register ("Page Faults", SYSCOUNTER_COUNT, &page_faults);
+ mono_counters_register ("CPU Load Average - 1min", SYSCOUNTER_LOAD, &cpu_load_1min);
+ mono_counters_register ("CPU Load Average - 5min", SYSCOUNTER_LOAD, &cpu_load_5min);
+ mono_counters_register ("CPU Load Average - 15min", SYSCOUNTER_LOAD, &cpu_load_15min);
+
+ system_counters_initialized = TRUE;
+}
/**
* mono_counters_foreach:
{
MonoCounter *counter;
+ if (!system_counters_initialized)
+ initialize_system_counters ();
+
for (counter = counters; counter; counter = counter->next) {
if (!cb (counter, user_data))
return;
size = sizeof (type); \
if (buffer_size < size) \
return -1; \
- type __var = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
- memcpy (buffer, &__var, size); \
+ *(type*)buffer = cb ? ((functype)counter->addr) () : *(type*)counter->addr; \
} while (0);
int
case MONO_COUNTER_STRING:
if (buffer_size < counter->size)
return -1;
+ if (counter->size == 0)
+ return 0;
strval = cb ? ((StrFunc)counter->addr) () : (char*)counter->addr;
if (!strval)
return 0;
size = counter->size;
strncpy (buffer, strval, size - 1);
- buffer[size - 1] = '\0';
+ ((char*)buffer)[size - 1] = '\0';
}
return size;