Merge pull request #409 from Alkarex/patch-1
[mono.git] / mono / metadata / mono-perfcounters.c
index 517688faa5e6c16da906a9bb660028fa3237ac7a..700cd9e498abc011709e879426d4189357fb14bf 100644 (file)
@@ -6,23 +6,38 @@
  * Author: Paolo Molaro (lupus@ximian.com)
  *
  * Copyright 2008-2009 Novell, Inc (http://www.novell.com)
+ * 2011 Xamarin, Inc
  */
 
 #include "config.h"
 #include <time.h>
 #include <string.h>
 #include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined (__OpenBSD__)
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#if defined (__NetBSD__) || defined (__APPLE__)
+#include <sys/sysctl.h>
+#endif
 #include "metadata/mono-perfcounters.h"
 #include "metadata/appdomain.h"
+#include "metadata/object-internals.h"
 /* for mono_stats */
 #include "metadata/class-internals.h"
 #include "utils/mono-time.h"
 #include "utils/mono-mmap.h"
 #include "utils/mono-proclib.h"
 #include "utils/mono-networkinterfaces.h"
+#include "utils/mono-error-internals.h"
 #include <mono/io-layer/io-layer.h>
 
 /* map of CounterSample.cs */
@@ -37,6 +52,7 @@ struct _MonoCounterSample {
        int counterType;
 };
 
+#ifndef DISABLE_PERFCOUNTERS
 /* map of PerformanceCounterType.cs */
 enum {
        NumberOfItemsHEX32=0x00000000,
@@ -378,6 +394,60 @@ predef_cleanup (ImplVtable *vtable)
        perfctr_unlock ();
 }
 
+static guint64
+mono_determine_physical_ram_size (void)
+{
+#if defined (TARGET_WIN32)
+       MEMORYSTATUSEX memstat;
+
+       memstat.dwLength = sizeof (memstat);
+       GlobalMemoryStatusEx (&memstat);
+       return (guint64)memstat.ullTotalPhys;
+#elif defined (__NetBSD__) || defined (__APPLE__)
+#ifdef __NetBSD__
+       unsigned long value;
+#else
+       guint64 value;
+#endif
+       int mib[2] = {
+               CTL_HW,
+#ifdef __NetBSD__
+               HW_PHYSMEM
+#else
+               HW_MEMSIZE
+#endif
+       };
+       size_t size_sys = sizeof (value);
+
+       sysctl (mib, 2, &value, &size_sys, NULL, 0);
+       if (value == 0)
+               return 134217728;
+
+       return (guint64)value;
+#elif defined (HAVE_SYSCONF)
+       guint64 page_size = 0, num_pages = 0;
+
+       /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
+        * reports invalid values, please add your OS specific code below. */
+#ifdef _SC_PAGESIZE
+       page_size = (guint64)sysconf (_SC_PAGESIZE);
+#endif
+
+#ifdef _SC_PHYS_PAGES
+       num_pages = (guint64)sysconf (_SC_PHYS_PAGES);
+#endif
+
+       if (!page_size || !num_pages) {
+               g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
+               return 134217728;
+       }
+
+       return page_size * num_pages;
+#else
+       return 134217728;
+#endif
+}
+
 void
 mono_perfcounters_init (void)
 {
@@ -744,11 +814,14 @@ network_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBool
        const CounterDesc *cdesc;
        NetworkVtableArg *narg;
        ImplVtable *vtable;
+       char *instance_name;
+
        *custom = FALSE;
        if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
+               instance_name = mono_string_to_utf8 (instance);
                narg = g_new0 (NetworkVtableArg, 1);
                narg->id = cdesc->id;
-               narg->name = mono_string_to_utf8 (instance);
+               narg->name = instance_name;
                *type = cdesc->type;
                vtable = create_vtable (narg, get_network_counter, NULL);
                vtable->cleanup = network_cleanup;
@@ -824,6 +897,9 @@ mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample
        case COUNTER_MEM_NUM_OBJECTS:
                sample->rawValue = mono_stats.new_object_count;
                return TRUE;
+       case COUNTER_MEM_PHYS_TOTAL:
+               sample->rawValue = mono_determine_physical_ram_size ();;
+               return TRUE;
        }
        return FALSE;
 }
@@ -924,6 +1000,31 @@ predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounter
                case COUNTER_THREADPOOL_IOWORKITEMS:
                        sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
                        return TRUE;
+               case COUNTER_THREADPOOL_THREADS:
+                       sample->rawValue = mono_perfcounters->threadpool_threads;
+                       return TRUE;
+               case COUNTER_THREADPOOL_IOTHREADS:
+                       sample->rawValue = mono_perfcounters->threadpool_iothreads;
+                       return TRUE;
+               }
+               break;
+       case CATEGORY_JIT:
+               switch (id) {
+               case COUNTER_JIT_BYTES:
+                       sample->rawValue = mono_perfcounters->jit_bytes;
+                       return TRUE;
+               case COUNTER_JIT_METHODS:
+                       sample->rawValue = mono_perfcounters->jit_methods;
+                       return TRUE;
+               case COUNTER_JIT_TIME:
+                       sample->rawValue = mono_perfcounters->jit_time;
+                       return TRUE;
+               case COUNTER_JIT_BYTES_PSEC:
+                       sample->rawValue = mono_perfcounters->jit_bytes;
+                       return TRUE;
+               case COUNTER_JIT_FAILURES:
+                       sample->rawValue = mono_perfcounters->jit_failures;
+                       return TRUE;
                }
                break;
        }
@@ -949,6 +1050,8 @@ predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
                switch (id) {
                case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
                case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
+               case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
+               case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
                }
                break;
        }
@@ -1271,27 +1374,37 @@ typedef struct {
 MonoBoolean
 mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
 {
+       MonoError error;
        int result = FALSE;
        int i, size;
        int num_counters = mono_array_length (items);
        int counters_data_size;
-       char *name;
-       char *chelp;
-       char **counter_info;
+       char *name = NULL;
+       char *chelp = NULL;
+       char **counter_info = NULL;
        unsigned char *ptr;
        char *p;
        SharedCategory *cat;
 
        /* FIXME: ensure there isn't a category created already */
-       name = mono_string_to_utf8 (category);
-       chelp = mono_string_to_utf8 (help);
+       mono_error_init (&error);
+       name = mono_string_to_utf8_checked (category, &error);
+       if (!mono_error_ok (&error))
+               goto failure;
+       chelp = mono_string_to_utf8_checked (help, &error);
+       if (!mono_error_ok (&error))
+               goto failure;
        counter_info = g_new0 (char*, num_counters * 2);
        /* calculate the size we need structure size + name/help + 2 0 string terminators */
        size = G_STRUCT_OFFSET (SharedCategory, name) + strlen (name) + strlen (chelp) + 2;
        for (i = 0; i < num_counters; ++i) {
                CounterCreationData *data = mono_array_get (items, CounterCreationData*, i);
-               counter_info [i * 2] = mono_string_to_utf8 (data->name);
-               counter_info [i * 2 + 1] = mono_string_to_utf8 (data->help);
+               counter_info [i * 2] = mono_string_to_utf8_checked (data->name, &error);
+               if (!mono_error_ok (&error))
+                       goto failure;
+               counter_info [i * 2 + 1] = mono_string_to_utf8_checked (data->help, &error);
+               if (!mono_error_ok (&error))
+                       goto failure;
                size += sizeof (SharedCounter) + 1; /* 1 is for the help 0 terminator */
        }
        for (i = 0; i < num_counters * 2; ++i) {
@@ -1336,12 +1449,15 @@ mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoA
        perfctr_unlock ();
        result = TRUE;
 failure:
-       for (i = 0; i < num_counters * 2; ++i) {
-               g_free (counter_info [i]);
+       if (counter_info) {
+               for (i = 0; i < num_counters * 2; ++i) {
+                       g_free (counter_info [i]);
+               }
+               g_free (counter_info);
        }
-       g_free (counter_info);
        g_free (name);
        g_free (chelp);
+       mono_error_cleanup (&error);
        return result;
 }
 
@@ -1493,12 +1609,14 @@ get_cpu_instances (void)
        void **buf = NULL;
        int i, count;
        MonoArray *array;
-       count = mono_cpu_count ();
+
+       count = mono_cpu_count () + 1; /* +1 for "_Total" */
        buf = g_new (void*, count);
        for (i = 0; i < count; ++i)
-               buf [i] = GINT_TO_POINTER (i);
+               buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
        array = get_string_array (buf, count, FALSE);
        g_free (buf);
+       mono_array_setref (array, 0, mono_string_new (mono_domain_get (), "_Total"));
        return array;
 }
 
@@ -1572,4 +1690,77 @@ mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
                return mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
        }
 }
+#else
+void*
+mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)
+{
+       g_assert_not_reached ();
+}
+
+MonoBoolean
+mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
+{
+       g_assert_not_reached ();
+}
 
+gint64
+mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
+{
+       g_assert_not_reached ();
+}
+
+void
+mono_perfcounter_free_data (void *impl)
+{
+       g_assert_not_reached ();
+}
+
+/* Category icalls */
+MonoBoolean
+mono_perfcounter_category_del (MonoString *name)
+{
+       g_assert_not_reached ();
+}
+
+MonoString*
+mono_perfcounter_category_help (MonoString *category, MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+
+MonoBoolean
+mono_perfcounter_category_exists (MonoString *counter, MonoString *category, MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+
+MonoBoolean
+mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoArray *items)
+{
+       g_assert_not_reached ();
+}
+
+int
+mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+
+MonoArray*
+mono_perfcounter_category_names (MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+
+MonoArray*
+mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+
+MonoArray*
+mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
+{
+       g_assert_not_reached ();
+}
+#endif