emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] emacs/src w32.c


From: Eli Zaretskii
Subject: [Emacs-diffs] emacs/src w32.c
Date: Sat, 04 Jul 2009 10:42:45 +0000

CVSROOT:        /cvsroot/emacs
Module name:    emacs
Changes by:     Eli Zaretskii <eliz>    09/07/04 10:42:45

Modified files:
        src            : w32.c 

Log message:
        Emulation of `getloadavg' on MS-Windows:
        Include float.h
        (g_b_init_get_native_system_info, g_b_init_get_system_times)
        (GetNativeSystemInfo_Proc, GetSystemTimes_Proc): Declare.
        (get_native_system_info, get_system_times): New functions.
        (buf_next, buf_prev, sample_system_load, getavg): New subroutines.
        (getloadavg): Rewrite using GetSystemTimes and GetNativeSystemInfo.
        (globals_of_w32): Initialize g_b_init_get_native_system_info,
        g_b_init_get_system_times, and num_of_processors.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/emacs/src/w32.c?cvsroot=emacs&r1=1.162&r2=1.163

Patches:
Index: w32.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/w32.c,v
retrieving revision 1.162
retrieving revision 1.163
diff -u -b -r1.162 -r1.163
--- w32.c       29 Jun 2009 05:28:55 -0000      1.162
+++ w32.c       4 Jul 2009 10:42:45 -0000       1.163
@@ -23,6 +23,7 @@
 #include <stddef.h> /* for offsetof */
 #include <stdlib.h>
 #include <stdio.h>
+#include <float.h>     /* for DBL_EPSILON */
 #include <io.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -191,6 +192,8 @@
 static BOOL g_b_init_get_length_sid;
 static BOOL g_b_init_equal_sid;
 static BOOL g_b_init_copy_sid;
+static BOOL g_b_init_get_native_system_info;
+static BOOL g_b_init_get_system_times;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -293,6 +296,12 @@
     PSID pSid2);
 typedef DWORD (WINAPI * GetLengthSid_Proc) (
     PSID pSid);
+typedef void (WINAPI * GetNativeSystemInfo_Proc) (
+    LPSYSTEM_INFO lpSystemInfo);
+typedef BOOL (WINAPI * GetSystemTimes_Proc) (
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime);
 
 
 
@@ -723,6 +732,47 @@
   supported in Windows NT / 2k / XP
 */
 
+void WINAPI get_native_system_info (
+    LPSYSTEM_INFO lpSystemInfo)
+{
+  static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
+  if (is_windows_9x () != TRUE)
+    {
+      if (g_b_init_get_native_system_info == 0)
+       {
+         g_b_init_get_native_system_info = 1;
+         s_pfn_Get_Native_System_Info =
+           (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle 
("kernel32.dll"),
+                                                     "GetNativeSystemInfo");
+       }
+      if (s_pfn_Get_Native_System_Info != NULL)
+       s_pfn_Get_Native_System_Info (lpSystemInfo);
+    }
+  else
+    lpSystemInfo->dwNumberOfProcessors = -1;
+}
+
+BOOL WINAPI get_system_times(
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime)
+{
+  static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_get_system_times == 0)
+    {
+      g_b_init_get_system_times = 1;
+      s_pfn_Get_System_times =
+       (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                                            "GetSystemTimes");
+    }
+  if (s_pfn_Get_System_times == NULL)
+    return FALSE;
+  return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
+}
 
 /* Equivalent of strerror for W32 error codes.  */
 char *
@@ -795,17 +845,160 @@
 #endif /* HAVE_SOCKETS */
 
 /* Emulate getloadavg.  */
+
+struct load_sample {
+  time_t sample_time;
+  ULONGLONG idle;
+  ULONGLONG kernel;
+  ULONGLONG user;
+};
+
+/* Number of processors on this machine.  */
+static unsigned num_of_processors;
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = sizeof (samples) / sizeof (samples[0]);
+
+static int
+buf_next (int from)
+{
+  int next_idx = from + 1;
+
+  if (next_idx >= max_idx)
+    next_idx = 0;
+
+  return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+  int prev_idx = from - 1;
+
+  if (prev_idx < 0)
+    prev_idx = max_idx - 1;
+
+  return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+  SYSTEM_INFO sysinfo;
+  FILETIME ft_idle, ft_user, ft_kernel;
+
+  /* Initialize the number of processors on this machine.  */
+  if (num_of_processors <= 0)
+    {
+      get_native_system_info (&sysinfo);
+      num_of_processors = sysinfo.dwNumberOfProcessors;
+      if (num_of_processors <= 0)
+       {
+         GetSystemInfo (&sysinfo);
+         num_of_processors = sysinfo.dwNumberOfProcessors;
+       }
+      if (num_of_processors <= 0)
+       num_of_processors = 1;
+    }
+
+  /* TODO: Take into account threads that are ready to run, by
+     sampling the "\System\Processor Queue Length" performance
+     counter.  The code below accounts only for threads that are
+     actually running.  */
+
+  if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+    {
+      ULARGE_INTEGER uidle, ukernel, uuser;
+
+      memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+      memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+      memcpy (&uuser, &ft_user, sizeof (ft_user));
+      *idle = uidle.QuadPart;
+      *kernel = ukernel.QuadPart;
+      *user = uuser.QuadPart;
+    }
+  else
+    {
+      *idle = 0;
+      *kernel = 0;
+      *user = 0;
+    }
+}
+
+/* Produce the load average for a given time interval, using the
+   samples in the samples[] array.  WHICH can be 0, 1, or 2, meaning
+   1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+  double retval = -1.0;
+  double tdiff;
+  int idx;
+  double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+  time_t now = samples[last_idx].sample_time;
+
+  if (first_idx != last_idx)
+    {
+      for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+       {
+         tdiff = difftime (now, samples[idx].sample_time);
+         if (tdiff >= span - 2*DBL_EPSILON*now)
+           {
+             long double sys =
+               samples[last_idx].kernel + samples[last_idx].user
+               - (samples[idx].kernel + samples[idx].user);
+             long double idl = samples[last_idx].idle - samples[idx].idle;
+
+             retval = (1.0 - idl / sys) * num_of_processors;
+             break;
+           }
+         if (idx == first_idx)
+           break;
+       }
+    }
+
+  return retval;
+}
+
 int
 getloadavg (double loadavg[], int nelem)
 {
-  int i;
+  int elem;
+  ULONGLONG idle, kernel, user;
+  time_t now = time (NULL);
+
+  /* Store another sample.  We ignore samples that are less than 1 sec
+     apart.  */
+  if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
+    {
+      sample_system_load (&idle, &kernel, &user);
+      last_idx = buf_next (last_idx);
+      samples[last_idx].sample_time = now;
+      samples[last_idx].idle = idle;
+      samples[last_idx].kernel = kernel;
+      samples[last_idx].user = user;
+      /* If the buffer has more that 15 min worth of samples, discard
+        the old ones.  */
+      if (first_idx == -1)
+       first_idx = last_idx;
+      while (first_idx != last_idx
+            && (difftime (now, samples[first_idx].sample_time)
+                >= 15.0*60 + 2*DBL_EPSILON*now))
+       first_idx = buf_next (first_idx);
+    }
 
-  /* A faithful emulation is going to have to be saved for a rainy day.  */
-  for (i = 0; i < nelem; i++)
+  for (elem = 0; elem < nelem; elem++)
     {
-      loadavg[i] = 0.0;
+      double avg = getavg (elem);
+
+      if (avg < 0)
+       break;
+      loadavg[elem] = avg;
     }
-  return i;
+
+  return elem;
 }
 
 /* Emulate getpwuid, getpwnam and others.  */
@@ -5693,6 +5886,9 @@
   g_b_init_equal_sid = 0;
   g_b_init_copy_sid = 0;
   g_b_init_get_length_sid = 0;
+  g_b_init_get_native_system_info = 0;
+  g_b_init_get_system_times = 0;
+  num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
      console apps. This actually applies to Emacs in both console and
      GUI modes, since we had to fool windows into thinking emacs is a




reply via email to

[Prev in Thread] Current Thread [Next in Thread]