2009-01-13 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / mono-perfcounters.c
index cd680d3987f368c9a05c07a2c9f19ef7a7b8040e..0fe450027fd0a023516fa6d0f34669d8ac78317e 100644 (file)
@@ -21,6 +21,7 @@
 #include "metadata/class-internals.h"
 #include "utils/mono-time.h"
 #include "utils/mono-mmap.h"
+#include "utils/mono-proclib.h"
 #include <mono/io-layer/io-layer.h>
 
 /* map of CounterSample.cs */
@@ -101,7 +102,7 @@ enum {
 };
 
 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_ ## id,
-#define PERFCTR_COUNTER(id,name,help,type)
+#define PERFCTR_COUNTER(id,name,help,type,field)
 enum {
 #include "mono-perfcounters-def.h"
        NUM_CATEGORIES
@@ -110,7 +111,7 @@ enum {
 #undef PERFCTR_CAT
 #undef PERFCTR_COUNTER
 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) CATEGORY_START_ ## id = -1,
-#define PERFCTR_COUNTER(id,name,help,type) COUNTER_ ## id,
+#define PERFCTR_COUNTER(id,name,help,type,field) COUNTER_ ## id,
 /* each counter is assigned an id starting from 0 inside the category */
 enum {
 #include "mono-perfcounters-def.h"
@@ -120,7 +121,7 @@ enum {
 #undef PERFCTR_CAT
 #undef PERFCTR_COUNTER
 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
-#define PERFCTR_COUNTER(id,name,help,type) CCOUNTER_ ## id,
+#define PERFCTR_COUNTER(id,name,help,type,field) CCOUNTER_ ## id,
 /* this is used just to count the number of counters */
 enum {
 #include "mono-perfcounters-def.h"
@@ -231,14 +232,15 @@ typedef struct {
 typedef struct {
        const char *name;
        const char *help;
-       int id;
+       short id;
+       unsigned short offset; // offset inside MonoPerfCounters
        int type;
 } CounterDesc;
 
 #undef PERFCTR_CAT
 #undef PERFCTR_COUNTER
 #define PERFCTR_CAT(id,name,help,type,inst,first_counter) {name, help, CATEGORY_ ## id, type, inst ## Instance, CCOUNTER_ ## first_counter},
-#define PERFCTR_COUNTER(id,name,help,type)
+#define PERFCTR_COUNTER(id,name,help,type,field)
 static const CategoryDesc
 predef_categories [] = {
 #include "mono-perfcounters-def.h"
@@ -248,11 +250,11 @@ predef_categories [] = {
 #undef PERFCTR_CAT
 #undef PERFCTR_COUNTER
 #define PERFCTR_CAT(id,name,help,type,inst,first_counter)
-#define PERFCTR_COUNTER(id,name,help,type) {name, help, COUNTER_ ## id, type},
+#define PERFCTR_COUNTER(id,name,help,type,field) {name, help, COUNTER_ ## id, G_STRUCT_OFFSET (MonoPerfCounters, field), type},
 static const CounterDesc
 predef_counters [] = {
 #include "mono-perfcounters-def.h"
-       {NULL, NULL, -1, 0}
+       {NULL, NULL, -1, 0, 0}
 };
 
 /*
@@ -561,50 +563,10 @@ id_from_string (MonoString *instance, gboolean is_process)
        return id;
 }
 
-static void
-get_cpu_times (int cpu_id, gint64 *user, gint64 *systemt, gint64 *irq, gint64 *sirq, gint64 *idle)
-{
-       SYSTEM_INFO info;
-       char buf [256];
-       char *s;
-       int hz = 100;
-       long long unsigned int user_ticks, nice_ticks, system_ticks, idle_ticks, iowait_ticks, irq_ticks, sirq_ticks;
-       FILE *f = fopen ("/proc/stat", "r");
-       if (!f)
-               return;
-       GetSystemInfo (&info);
-       hz *= info.dwNumberOfProcessors;
-       while ((s = fgets (buf, sizeof (buf), f))) {
-               char *data = NULL;
-               if (cpu_id < 0 && strncmp (s, "cpu", 3) == 0 && g_ascii_isspace (s [3])) {
-                       data = s + 4;
-               } else if (cpu_id >= 0 && strncmp (s, "cpu", 3) == 0 && strtol (s + 3, &data, 10) == cpu_id) {
-                       if (data == s + 3)
-                               continue;
-                       data++;
-               } else {
-                       continue;
-               }
-               sscanf (data, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu", &user_ticks, &nice_ticks, &system_ticks, &idle_ticks, &iowait_ticks, &irq_ticks, &sirq_ticks);
-       }
-       fclose (f);
-
-       if (user)
-               *user = (user_ticks + nice_ticks) * 10000000 / hz;
-       if (systemt)
-               *systemt = (system_ticks) * 10000000 / hz;
-       if (irq)
-               *irq = (irq_ticks) * 10000000 / hz;
-       if (sirq)
-               *sirq = (sirq_ticks) * 10000000 / hz;
-       if (idle)
-               *idle = (idle_ticks) * 10000000 / hz;
-}
-
 static MonoBoolean
 get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
 {
-       gint64 value = 0;
+       MonoProcessError error;
        int id = GPOINTER_TO_INT (vtable->arg);
        int pid = id >> 5;
        id &= 0x1f;
@@ -615,24 +577,19 @@ get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *
        sample->counterType = predef_counters [predef_categories [CATEGORY_CPU].first_counter + id].type;
        switch (id) {
        case COUNTER_CPU_USER_TIME:
-               get_cpu_times (pid, &value, NULL, NULL, NULL, NULL);
-               sample->rawValue = value;
+               sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_USER_TIME, &error);
                return TRUE;
        case COUNTER_CPU_PRIV_TIME:
-               get_cpu_times (pid, NULL, &value, NULL, NULL, NULL);
-               sample->rawValue = value;
+               sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_PRIV_TIME, &error);
                return TRUE;
        case COUNTER_CPU_INTR_TIME:
-               get_cpu_times (pid, NULL, NULL, &value, NULL, NULL);
-               sample->rawValue = value;
+               sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_INTR_TIME, &error);
                return TRUE;
        case COUNTER_CPU_DCP_TIME:
-               get_cpu_times (pid, NULL, NULL, NULL, &value, NULL);
-               sample->rawValue = value;
+               sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_DCP_TIME, &error);
                return TRUE;
        case COUNTER_CPU_PROC_TIME:
-               get_cpu_times (pid, NULL, NULL, NULL, NULL, &value);
-               sample->rawValue = value;
+               sample->rawValue = mono_cpu_get_data (pid, MONO_CPU_IDLE_TIME, &error);
                return TRUE;
        }
        return FALSE;
@@ -653,89 +610,6 @@ cpu_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean
        return NULL;
 }
 
-/*
- * /proc/pid/stat format:
- * pid (cmdname) S 
- *     [0] ppid pgid sid tty_nr tty_pgrp flags min_flt cmin_flt maj_flt cmaj_flt
- *     [10] utime stime cutime cstime prio nice threads start_time vsize rss
- *     [20] rsslim start_code end_code start_stack esp eip pending blocked sigign sigcatch
- *     [30] wchan 0 0 exit_signal cpu rt_prio policy
- */
-
-static gint64
-get_process_time (int pid, int pos, int sum)
-{
-       char buf [512];
-       char *s, *end;
-       FILE *f;
-       int len, i;
-       gint64 value;
-
-       g_snprintf (buf, sizeof (buf), "/proc/%d/stat", pid);
-       f = fopen (buf, "r");
-       if (!f)
-               return 0;
-       len = fread (buf, 1, sizeof (buf), f);
-       fclose (f);
-       if (len <= 0)
-               return 0;
-       s = strchr (buf, ')');
-       if (!s)
-               return 0;
-       s++;
-       while (g_ascii_isspace (*s)) s++;
-       if (!*s)
-               return 0;
-       /* skip the status char */
-       while (*s && !g_ascii_isspace (*s)) s++;
-       if (!*s)
-               return 0;
-       for (i = 0; i < pos; ++i) {
-               while (g_ascii_isspace (*s)) s++;
-               if (!*s)
-                       return 0;
-               while (*s && !g_ascii_isspace (*s)) s++;
-               if (!*s)
-                       return 0;
-       }
-       /* we are finally at the needed item */
-       value = strtoul (s, &end, 0);
-       /* add also the following value */
-       if (sum) {
-               while (g_ascii_isspace (*s)) s++;
-               if (!*s)
-                       return 0;
-               value += strtoul (s, &end, 0);
-       }
-       return value;
-}
-
-static gint64
-get_pid_stat_item (int pid, const char *item)
-{
-       char buf [256];
-       char *s;
-       FILE *f;
-       int len = strlen (item);
-
-       g_snprintf (buf, sizeof (buf), "/proc/%d/status", pid);
-       f = fopen (buf, "r");
-       if (!f)
-               return 0;
-       while ((s = fgets (buf, sizeof (buf), f))) {
-               if (*item != *buf)
-                       continue;
-               if (strncmp (buf, item, len))
-                       continue;
-               if (buf [len] != ':')
-                       continue;
-               fclose (f);
-               return atoi (buf + len + 1);
-       }
-       fclose (f);
-       return 0;
-}
-
 static MonoBoolean
 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
 {
@@ -751,25 +625,25 @@ get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSamp
        sample->counterType = predef_counters [predef_categories [CATEGORY_PROC].first_counter + id].type;
        switch (id) {
        case COUNTER_PROC_USER_TIME:
-               sample->rawValue = get_process_time (pid, 12, FALSE);
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_USER_TIME);
                return TRUE;
        case COUNTER_PROC_PRIV_TIME:
-               sample->rawValue = get_process_time (pid, 13, FALSE);
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_SYSTEM_TIME);
                return TRUE;
        case COUNTER_PROC_PROC_TIME:
-               sample->rawValue = get_process_time (pid, 12, TRUE);
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_TOTAL_TIME);
                return TRUE;
        case COUNTER_PROC_THREADS:
-               sample->rawValue = get_pid_stat_item (pid, "Threads");
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_NUM_THREADS);
                return TRUE;
        case COUNTER_PROC_VBYTES:
-               sample->rawValue = get_pid_stat_item (pid, "VmSize") * 1024;
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_VIRTUAL_BYTES);
                return TRUE;
        case COUNTER_PROC_WSET:
-               sample->rawValue = get_pid_stat_item (pid, "VmRSS") * 1024;
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_WORKING_SET);
                return TRUE;
        case COUNTER_PROC_PBYTES:
-               sample->rawValue = get_pid_stat_item (pid, "VmData") * 1024;
+               sample->rawValue = mono_process_get_data (GINT_TO_POINTER (pid), MONO_PROCESS_PRIVATE_BYTES);
                return TRUE;
        }
        return FALSE;
@@ -814,7 +688,7 @@ mono_mem_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoo
        *custom = FALSE;
        if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_MONO_MEM], counter))) {
                *type = cdesc->type;
-               return create_vtable (GINT_TO_POINTER (cdesc->id), mono_mem_counter, NULL);
+               return create_vtable (GINT_TO_POINTER ((gint) cdesc->id), mono_mem_counter, NULL);
        }
        return NULL;
 }
@@ -823,6 +697,7 @@ static MonoBoolean
 predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
 {
        PredefVtable *vt = (PredefVtable *)vtable;
+       const CounterDesc *desc;
        int cat_id = GPOINTER_TO_INT (vtable->arg);
        int id = cat_id >> 16;
        cat_id &= 0xffff;
@@ -830,36 +705,12 @@ predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounter
                fill_sample (sample);
                sample->baseValue = 1;
        }
-       sample->counterType = predef_counters [predef_categories [cat_id].first_counter + id].type;
-       switch (cat_id) {
-       case CATEGORY_JIT:
-               switch (id) {
-               case COUNTER_JIT_BYTES:
-               case COUNTER_JIT_BYTES_PSEC:
-                       sample->rawValue = vt->counters->jit_bytes;
-                       return TRUE;
-               case COUNTER_JIT_METHODS:
-                       sample->rawValue = vt->counters->jit_methods;
-                       return TRUE;
-               }
-               break;
-       case CATEGORY_EXC:
-               switch (id) {
-               case COUNTER_EXC_THROWN:
-               case COUNTER_EXC_THROWN_PSEC:
-                       sample->rawValue = vt->counters->exceptions_thrown;
-                       return TRUE;
-               }
-               break;
-
-       case CATEGORY_ASPNET:
-               switch (id) {
-               case COUNTER_ASPNET_REQ_Q:
-                       sample->rawValue = vt->counters->aspnet_requests_queued;
-                       return TRUE;
-               }
-       }
-       return FALSE;
+       desc = &predef_counters [predef_categories [cat_id].first_counter + id];
+       sample->counterType = desc->type;
+       /* FIXME: check that the offset fits inside imported counters */
+       /*g_print ("loading %s at %d\n", desc->name, desc->offset);*/
+       sample->rawValue = *(guint32*)((char*)vt->counters + desc->offset);
+       return TRUE;
 }
 
 static ImplVtable*
@@ -880,7 +731,7 @@ predef_vtable (void *arg, MonoString *instance)
        vtable->vtable.arg = arg;
        vtable->vtable.sample = predef_readonly_counter;
        vtable->vtable.cleanup = predef_cleanup;
-       vtable->counters = &area->counters;
+       vtable->counters = (MonoPerfCounters*)((char*)area + area->counters_start);
        vtable->pid = pid;
 
        return (ImplVtable*)vtable;
@@ -1035,6 +886,12 @@ mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString
                return mono_mem_get_impl (counter, instance, type, custom);
        case CATEGORY_JIT:
        case CATEGORY_EXC:
+       case CATEGORY_GC:
+       case CATEGORY_REMOTING:
+       case CATEGORY_LOADING:
+       case CATEGORY_THREAD:
+       case CATEGORY_INTEROP:
+       case CATEGORY_SECURITY:
        case CATEGORY_ASPNET:
                return predef_writable_get_impl (cdesc->id, counter, instance, type, custom);
        }
@@ -1297,27 +1154,6 @@ mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
        return mono_array_new (domain, mono_get_string_class (), 0);
 }
 
-static char*
-read_proc_name (int pid, char *buf, int len)
-{
-       char fname [128];
-       FILE *file;
-       char *p;
-       int r;
-       sprintf (fname, "/proc/%d/cmdline", pid);
-       buf [0] = 0;
-       file = fopen (fname, "r");
-       if (!file)
-               return buf;
-       r = fread (buf, 1, len - 1, file);
-       fclose (file);
-       buf [r] = 0;
-       p = strrchr (buf, '/');
-       if (p)
-               return p + 1;
-       return buf;
-}
-
 static MonoArray*
 get_string_array (void **array, int count, gboolean is_process)
 {
@@ -1328,7 +1164,7 @@ get_string_array (void **array, int count, gboolean is_process)
                char buf [128];
                char *p;
                if (is_process) {
-                       char *pname = read_proc_name (GPOINTER_TO_INT (array [i]), buf, sizeof (buf));
+                       char *pname = mono_process_get_name (array [i], buf, sizeof (buf));
                        p = g_strdup_printf ("%d/%s", GPOINTER_TO_INT (array [i]), pname);
                } else {
                        sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
@@ -1363,14 +1199,13 @@ static MonoArray*
 get_cpu_instances (void)
 {
        void **buf = NULL;
-       int i;
+       int i, count;
        MonoArray *array;
-       SYSTEM_INFO info;
-       GetSystemInfo (&info);
-       buf = g_new (void*, info.dwNumberOfProcessors);
-       for (i = 0; i < info.dwNumberOfProcessors; ++i)
+       count = mono_cpu_count ();
+       buf = g_new (void*, count);
+       for (i = 0; i < count; ++i)
                buf [i] = GINT_TO_POINTER (i);
-       array = get_string_array (buf, info.dwNumberOfProcessors, FALSE);
+       array = get_string_array (buf, count, FALSE);
        g_free (buf);
        return array;
 }
@@ -1378,31 +1213,12 @@ get_cpu_instances (void)
 static MonoArray*
 get_processes_instances (void)
 {
-       const char *name;
-       void **buf = NULL;
-       int count = 0;
-       int i = 0;
        MonoArray *array;
-       GDir *dir = g_dir_open ("/proc/", 0, NULL);
-       if (!dir)
+       int count = 0;
+       void **buf = mono_process_list (&count);
+       if (!buf)
                return get_string_array (NULL, 0, FALSE);
-       while ((name = g_dir_read_name (dir))) {
-               int pid;
-               char *nend;
-               pid = strtol (name, &nend, 10);
-               if (pid <= 0 || nend == name || *nend)
-                       continue;
-               if (i >= count) {
-                       if (!count)
-                               count = 16;
-                       else
-                               count *= 2;
-                       buf = g_realloc (buf, count * sizeof (void*));
-               }
-               buf [i++] = GINT_TO_POINTER (pid);
-       }
-       g_dir_close (dir);
-       array = get_string_array (buf, i, TRUE);
+       array = get_string_array (buf, count, TRUE);
        g_free (buf);
        return array;
 }