Merge pull request #1624 from esdrubal/getprocesstimes
[mono.git] / mono / utils / mono-proclib.c
index f8f177bbbe8aeec8f13de9bc7a214c60d5a6a68a..26d78cccfa59e4b5182e580c1c37056f9bc7f214 100644 (file)
 #include <process.h>
 #endif
 
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#if defined(_POSIX_VERSION)
 #include <sys/errno.h>
 #include <sys/param.h>
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SYSCTL_H
 #include <sys/sysctl.h>
+#endif
+#include <sys/resource.h>
+#endif
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
 #include <sys/proc.h>
 #if defined(__APPLE__)
 #include <mach/mach.h>
@@ -306,8 +313,13 @@ mono_process_get_times (gpointer pid, gint64 *start_time, gint64 *user_time, gin
                }
 #endif
 
-               if (*start_time == 0)
-                       *start_time = mono_process_get_data (pid, MONO_PROCESS_ELAPSED);
+               if (*start_time == 0) {
+                       static guint64 boot_time = 0;
+                       if (!boot_time)
+                               boot_time = mono_100ns_datetime () - ((guint64)mono_msec_ticks ()) * 10000;
+
+                       *start_time = boot_time + mono_process_get_data (pid, MONO_PROCESS_ELAPSED);
+               }
        }
 }
 
@@ -315,7 +327,7 @@ mono_process_get_times (gpointer pid, gint64 *start_time, gint64 *user_time, gin
  * /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 0 start_time vsize rss
+ *     [10] utime stime cutime cstime prio nice threads 0 start_time vsize
  *     [20] rss rsslim start_code end_code start_stack esp eip pending blocked sigign
  *     [30] sigcatch wchan 0 0 exit_signal cpu rt_prio policy
  */
@@ -550,7 +562,7 @@ mono_process_get_data_with_error (gpointer pid, MonoProcessData data, MonoProces
        case MONO_PROCESS_FAULTS:
                return get_process_stat_item (rpid, 6, TRUE, error);
        case MONO_PROCESS_ELAPSED:
-               return get_process_stat_item (rpid, 18, FALSE, error) / get_user_hz ();
+               return get_process_stat_time (rpid, 18, FALSE, error);
        case MONO_PROCESS_PPID:
                return get_process_stat_time (rpid, 0, FALSE, error);
        case MONO_PROCESS_PAGED_BYTES:
@@ -731,3 +743,62 @@ mono_atexit (void (*func)(void))
        return atexit (func);
 #endif
 }
+
+gint32
+mono_cpu_usage (MonoCpuUsageState *prev)
+{
+       gint32 cpu_usage = 0;
+       gint64 cpu_total_time;
+       gint64 cpu_busy_time;
+
+#ifndef HOST_WIN32
+       struct rusage resource_usage;
+       gint64 current_time;
+       gint64 kernel_time;
+       gint64 user_time;
+
+       if (getrusage (RUSAGE_SELF, &resource_usage) == -1) {
+               g_error ("getrusage() failed, errno is %d (%s)\n", errno, strerror (errno));
+               return -1;
+       }
+
+       current_time = mono_100ns_ticks ();
+       kernel_time = resource_usage.ru_stime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_stime.tv_usec * 10;
+       user_time = resource_usage.ru_utime.tv_sec * 1000 * 1000 * 10 + resource_usage.ru_utime.tv_usec * 10;
+
+       cpu_busy_time = (user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0));
+       cpu_total_time = (current_time - (prev ? prev->current_time : 0)) * mono_cpu_count ();
+
+       if (prev) {
+               prev->kernel_time = kernel_time;
+               prev->user_time = user_time;
+               prev->current_time = current_time;
+       }
+#else
+       guint64 idle_time;
+       guint64 kernel_time;
+       guint64 user_time;
+
+       if (!GetSystemTimes ((FILETIME*) &idle_time, (FILETIME*) &kernel_time, (FILETIME*) &user_time)) {
+               g_error ("GetSystemTimes() failed, error code is %d\n", GetLastError ());
+               return -1;
+       }
+
+       cpu_total_time = (gint64)((user_time - (prev ? prev->user_time : 0)) + (kernel_time - (prev ? prev->kernel_time : 0)));
+       cpu_busy_time = (gint64)(cpu_total_time - (idle_time - (prev ? prev->idle_time : 0)));
+
+       if (prev) {
+               prev->idle_time = idle_time;
+               prev->kernel_time = kernel_time;
+               prev->user_time = user_time;
+       }
+#endif
+
+       if (cpu_total_time > 0 && cpu_busy_time > 0)
+               cpu_usage = (gint32)(cpu_busy_time * 100 / cpu_total_time);
+
+       g_assert (cpu_usage >= 0);
+       g_assert (cpu_usage <= 100);
+
+       return cpu_usage;
+}