[counters] Add mono_counters_foreach API.
[mono.git] / mono / utils / mono-counters.c
index a12a528d6d14550007c9c918149515bf038a9fe6..e60520a8bed500ffc05b50544b9ac09651a3e6b3 100644 (file)
@@ -1,9 +1,12 @@
+/*
+ * Copyright 2006-2010 Novell
+ * Copyright 2011 Xamarin Inc
+ */
+
 #include <stdlib.h>
 #include <glib.h>
 #include "mono-counters.h"
 
-typedef struct _MonoCounter MonoCounter;
-
 struct _MonoCounter {
        MonoCounter *next;
        const char *name;
@@ -13,6 +16,19 @@ struct _MonoCounter {
 
 static MonoCounter *counters = NULL;
 static int valid_mask = 0;
+static int set_mask = 0;
+
+static int
+mono_counter_get_variance (MonoCounter *counter)
+{
+       return counter->type & MONO_COUNTER_VARIANCE_MASK;
+}
+
+static int
+mono_counter_get_unit (MonoCounter *counter)
+{
+       return counter->type & MONO_COUNTER_UNIT_MASK;
+}
 
 /**
  * mono_counters_enable:
@@ -33,6 +49,8 @@ mono_counters_enable (int section_mask)
  * @addr: The address to register.
  *
  * Register addr as the address of a counter of type type.
+ * Note that @name must be a valid string at all times until
+ * mono_counters_dump () is called.
  *
  * It may be a function pointer if MONO_COUNTER_CALLBACK is specified:
  * the function should return the value and take no arguments.
@@ -51,6 +69,8 @@ mono_counters_register (const char* name, int type, void *addr)
        counter->addr = addr;
        counter->next = NULL;
 
+       set_mask |= type;
+
        /* Append */
        if (counters) {
                MonoCounter *item = counters;
@@ -70,7 +90,7 @@ typedef gssize (*PtrFunc) (void);
 typedef double (*DoubleFunc) (void);
 typedef char* (*StrFunc) (void);
 
-#define ENTRY_FMT "%-24s : "
+#define ENTRY_FMT "%-36s: "
 static void
 dump_counter (MonoCounter *counter, FILE *outfile) {
        int intval;
@@ -100,32 +120,31 @@ dump_counter (MonoCounter *counter, FILE *outfile) {
                      int64val = ((LongFunc)counter->addr) ();
              else
                      int64val = *(gint64*)counter->addr;
-             fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, int64val);
+             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;
        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, uint64val);
+             fprintf (outfile, ENTRY_FMT "%llu\n", counter->name, (unsigned long long)uint64val);
              break;
        case MONO_COUNTER_WORD:
              if (counter->type & MONO_COUNTER_CALLBACK)
                      wordval = ((PtrFunc)counter->addr) ();
              else
                      wordval = *(gssize*)counter->addr;
-#if SIZEOF_VOID_P == 8
-             fprintf (outfile, ENTRY_FMT "%lld\n", counter->name, (gint64)wordval);
-#else
-             fprintf (outfile, ENTRY_FMT "%d\n", counter->name, wordval);
-#endif
+             fprintf (outfile, ENTRY_FMT "%zd\n", counter->name, (gint64)wordval);
              break;
        case MONO_COUNTER_DOUBLE:
              if (counter->type & MONO_COUNTER_CALLBACK)
                      dval = ((DoubleFunc)counter->addr) ();
              else
                      dval = *(double*)counter->addr;
-             fprintf (outfile, ENTRY_FMT "%.2f\n", counter->name, dval);
+             fprintf (outfile, ENTRY_FMT "%.4f\n", counter->name, dval);
              break;
        case MONO_COUNTER_STRING:
              if (counter->type & MONO_COUNTER_CALLBACK)
@@ -137,13 +156,26 @@ dump_counter (MonoCounter *counter, FILE *outfile) {
        }
 }
 
+void
+mono_counters_foreach (CountersEnumCallback cb, gpointer user_data)
+{
+       MonoCounter *counter;
+
+       for (counter = counters; counter; counter = counter->next) {
+               if (!cb (counter, user_data))
+                       return;
+       }
+}
+
 static const char
 section_names [][10] = {
        "JIT",
        "GC",
        "Metadata",
        "Generics",
-       "Security"
+       "Security",
+       "Runtime",
+       "System",
 };
 
 static void
@@ -151,7 +183,7 @@ mono_counters_dump_section (int section, FILE *outfile)
 {
        MonoCounter *counter = counters;
        while (counter) {
-               if (counter->type & section)
+               if (counter->type & section && mono_counter_get_variance (counter) == MONO_COUNTER_MONOTONIC)
                        dump_counter (counter, outfile);
                counter = counter->next;
        }
@@ -172,10 +204,95 @@ mono_counters_dump (int section_mask, FILE *outfile)
        if (!counters)
                return;
        for (j = 0, i = MONO_COUNTER_JIT; i < MONO_COUNTER_LAST_SECTION; j++, i <<= 1) {
-               if (section_mask & i) {
+               if ((section_mask & i) && (set_mask & i)) {
                        fprintf (outfile, "\n%s statistics\n", section_names [j]);
                        mono_counters_dump_section (i, outfile);
                }
        }
+
+       fflush (outfile);
 }
 
+/**
+ * mono_counters_cleanup:
+ *
+ * Perform any needed cleanup at process exit.
+ */
+void
+mono_counters_cleanup (void)
+{
+       MonoCounter *counter = counters;
+       counters = NULL;
+       while (counter) {
+               MonoCounter *tmp = counter;
+               counter = counter->next;
+               free (tmp);
+       }
+}
+
+static MonoResourceCallback limit_reached = NULL;
+static uintptr_t resource_limits [MONO_RESOURCE_COUNT * 2];
+
+/**
+ * mono_runtime_resource_check_limit:
+ * @resource_type: one of the #MonoResourceType enum values
+ * @value: the current value of the resource usage
+ *
+ * Check if a runtime resource limit has been reached. This function
+ * is intended to be used by the runtime only.
+ */
+void
+mono_runtime_resource_check_limit (int resource_type, uintptr_t value)
+{
+       if (!limit_reached)
+               return;
+       /* check the hard limit first */
+       if (value > resource_limits [resource_type * 2 + 1]) {
+               limit_reached (resource_type, value, 0);
+               return;
+       }
+       if (value > resource_limits [resource_type * 2])
+               limit_reached (resource_type, value, 1);
+}
+
+/**
+ * mono_runtime_resource_limit:
+ * @resource_type: one of the #MonoResourceType enum values
+ * @soft_limit: the soft limit value
+ * @hard_limit: the hard limit value
+ *
+ * This function sets the soft and hard limit for runtime resources. When the limit
+ * is reached, a user-specified callback is called. The callback runs in a restricted
+ * environment, in which the world coult be stopped, so it can't take locks, perform
+ * allocations etc. The callback may be called multiple times once a limit has been reached
+ * if action is not taken to decrease the resource use.
+ *
+ * Returns: 0 on error or a positive integer otherwise.
+ */
+int
+mono_runtime_resource_limit (int resource_type, uintptr_t soft_limit, uintptr_t hard_limit)
+{
+       if (resource_type >= MONO_RESOURCE_COUNT || resource_type < 0)
+               return 0;
+       if (soft_limit > hard_limit)
+               return 0;
+       resource_limits [resource_type * 2] = soft_limit;
+       resource_limits [resource_type * 2 + 1] = hard_limit;
+       return 1;
+}
+
+/**
+ * mono_runtime_resource_set_callback:
+ * @callback: a function pointer
+ * 
+ * Set the callback to be invoked when a resource limit is reached.
+ * The callback will receive the resource type, the resource amount in resource-specific
+ * units and a flag indicating whether the soft or hard limit was reached.
+ */
+void
+mono_runtime_resource_set_callback (MonoResourceCallback callback)
+{
+       limit_reached = callback;
+}
+
+