* 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 */
int counterType;
};
+#ifndef DISABLE_PERFCOUNTERS
/* map of PerformanceCounterType.cs */
enum {
NumberOfItemsHEX32=0x00000000,
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)
{
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;
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;
}
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;
}
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;
}
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) {
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;
}
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;
}
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