aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2009-07-04 10:43:10 +0000
committerEli Zaretskii2009-07-04 10:43:10 +0000
commitad9e2d54dd85944547f1333a616098e92f114850 (patch)
tree7b4dd9c2cb8a7cccf733c6dec15d91b6779c2ffe /src
parent7df24305ed8d85172aaa9084ed5b3f7d8e354bba (diff)
downloademacs-ad9e2d54dd85944547f1333a616098e92f114850.tar.gz
emacs-ad9e2d54dd85944547f1333a616098e92f114850.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog12
-rw-r--r--src/w32.c206
2 files changed, 213 insertions, 5 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index a74db6a2660..9da5a0871bd 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
12009-07-04 Eli Zaretskii <eliz@gnu.org>
2
3 Emulation of `getloadavg' on MS-Windows.
4 * w32.c: Include float.h
5 (g_b_init_get_native_system_info, g_b_init_get_system_times)
6 (GetNativeSystemInfo_Proc, GetSystemTimes_Proc): Declare.
7 (get_native_system_info, get_system_times): New functions.
8 (buf_next, buf_prev, sample_system_load, getavg): New subroutines.
9 (getloadavg): Rewrite using GetSystemTimes and GetNativeSystemInfo.
10 (globals_of_w32): Initialize g_b_init_get_native_system_info,
11 g_b_init_get_system_times, and num_of_processors.
12
12009-07-03 Jason Rumney <jasonr@gnu.org> 132009-07-03 Jason Rumney <jasonr@gnu.org>
2 14
3 * w32term.c (w32_initialize): Use standard types. 15 * w32term.c (w32_initialize): Use standard types.
diff --git a/src/w32.c b/src/w32.c
index 23da0bad937..ef0272259c4 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23#include <stddef.h> /* for offsetof */ 23#include <stddef.h> /* for offsetof */
24#include <stdlib.h> 24#include <stdlib.h>
25#include <stdio.h> 25#include <stdio.h>
26#include <float.h> /* for DBL_EPSILON */
26#include <io.h> 27#include <io.h>
27#include <errno.h> 28#include <errno.h>
28#include <fcntl.h> 29#include <fcntl.h>
@@ -191,6 +192,8 @@ static BOOL g_b_init_global_memory_status_ex;
191static BOOL g_b_init_get_length_sid; 192static BOOL g_b_init_get_length_sid;
192static BOOL g_b_init_equal_sid; 193static BOOL g_b_init_equal_sid;
193static BOOL g_b_init_copy_sid; 194static BOOL g_b_init_copy_sid;
195static BOOL g_b_init_get_native_system_info;
196static BOOL g_b_init_get_system_times;
194 197
195/* 198/*
196 BEGIN: Wrapper functions around OpenProcessToken 199 BEGIN: Wrapper functions around OpenProcessToken
@@ -293,6 +296,12 @@ typedef BOOL (WINAPI * EqualSid_Proc) (
293 PSID pSid2); 296 PSID pSid2);
294typedef DWORD (WINAPI * GetLengthSid_Proc) ( 297typedef DWORD (WINAPI * GetLengthSid_Proc) (
295 PSID pSid); 298 PSID pSid);
299typedef void (WINAPI * GetNativeSystemInfo_Proc) (
300 LPSYSTEM_INFO lpSystemInfo);
301typedef BOOL (WINAPI * GetSystemTimes_Proc) (
302 LPFILETIME lpIdleTime,
303 LPFILETIME lpKernelTime,
304 LPFILETIME lpUserTime);
296 305
297 306
298 307
@@ -723,6 +732,47 @@ BOOL WINAPI copy_sid (
723 supported in Windows NT / 2k / XP 732 supported in Windows NT / 2k / XP
724*/ 733*/
725 734
735void WINAPI get_native_system_info (
736 LPSYSTEM_INFO lpSystemInfo)
737{
738 static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
739 if (is_windows_9x () != TRUE)
740 {
741 if (g_b_init_get_native_system_info == 0)
742 {
743 g_b_init_get_native_system_info = 1;
744 s_pfn_Get_Native_System_Info =
745 (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
746 "GetNativeSystemInfo");
747 }
748 if (s_pfn_Get_Native_System_Info != NULL)
749 s_pfn_Get_Native_System_Info (lpSystemInfo);
750 }
751 else
752 lpSystemInfo->dwNumberOfProcessors = -1;
753}
754
755BOOL WINAPI get_system_times(
756 LPFILETIME lpIdleTime,
757 LPFILETIME lpKernelTime,
758 LPFILETIME lpUserTime)
759{
760 static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
761 if (is_windows_9x () == TRUE)
762 {
763 return FALSE;
764 }
765 if (g_b_init_get_system_times == 0)
766 {
767 g_b_init_get_system_times = 1;
768 s_pfn_Get_System_times =
769 (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
770 "GetSystemTimes");
771 }
772 if (s_pfn_Get_System_times == NULL)
773 return FALSE;
774 return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
775}
726 776
727/* Equivalent of strerror for W32 error codes. */ 777/* Equivalent of strerror for W32 error codes. */
728char * 778char *
@@ -795,17 +845,160 @@ gethostname (char *buffer, int size)
795#endif /* HAVE_SOCKETS */ 845#endif /* HAVE_SOCKETS */
796 846
797/* Emulate getloadavg. */ 847/* Emulate getloadavg. */
848
849struct load_sample {
850 time_t sample_time;
851 ULONGLONG idle;
852 ULONGLONG kernel;
853 ULONGLONG user;
854};
855
856/* Number of processors on this machine. */
857static unsigned num_of_processors;
858
859/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
860static struct load_sample samples[16*60];
861static int first_idx = -1, last_idx = -1;
862static int max_idx = sizeof (samples) / sizeof (samples[0]);
863
864static int
865buf_next (int from)
866{
867 int next_idx = from + 1;
868
869 if (next_idx >= max_idx)
870 next_idx = 0;
871
872 return next_idx;
873}
874
875static int
876buf_prev (int from)
877{
878 int prev_idx = from - 1;
879
880 if (prev_idx < 0)
881 prev_idx = max_idx - 1;
882
883 return prev_idx;
884}
885
886static void
887sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
888{
889 SYSTEM_INFO sysinfo;
890 FILETIME ft_idle, ft_user, ft_kernel;
891
892 /* Initialize the number of processors on this machine. */
893 if (num_of_processors <= 0)
894 {
895 get_native_system_info (&sysinfo);
896 num_of_processors = sysinfo.dwNumberOfProcessors;
897 if (num_of_processors <= 0)
898 {
899 GetSystemInfo (&sysinfo);
900 num_of_processors = sysinfo.dwNumberOfProcessors;
901 }
902 if (num_of_processors <= 0)
903 num_of_processors = 1;
904 }
905
906 /* TODO: Take into account threads that are ready to run, by
907 sampling the "\System\Processor Queue Length" performance
908 counter. The code below accounts only for threads that are
909 actually running. */
910
911 if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
912 {
913 ULARGE_INTEGER uidle, ukernel, uuser;
914
915 memcpy (&uidle, &ft_idle, sizeof (ft_idle));
916 memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
917 memcpy (&uuser, &ft_user, sizeof (ft_user));
918 *idle = uidle.QuadPart;
919 *kernel = ukernel.QuadPart;
920 *user = uuser.QuadPart;
921 }
922 else
923 {
924 *idle = 0;
925 *kernel = 0;
926 *user = 0;
927 }
928}
929
930/* Produce the load average for a given time interval, using the
931 samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
932 1-minute, 5-minute, or 15-minute average, respectively. */
933static double
934getavg (int which)
935{
936 double retval = -1.0;
937 double tdiff;
938 int idx;
939 double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
940 time_t now = samples[last_idx].sample_time;
941
942 if (first_idx != last_idx)
943 {
944 for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
945 {
946 tdiff = difftime (now, samples[idx].sample_time);
947 if (tdiff >= span - 2*DBL_EPSILON*now)
948 {
949 long double sys =
950 samples[last_idx].kernel + samples[last_idx].user
951 - (samples[idx].kernel + samples[idx].user);
952 long double idl = samples[last_idx].idle - samples[idx].idle;
953
954 retval = (1.0 - idl / sys) * num_of_processors;
955 break;
956 }
957 if (idx == first_idx)
958 break;
959 }
960 }
961
962 return retval;
963}
964
798int 965int
799getloadavg (double loadavg[], int nelem) 966getloadavg (double loadavg[], int nelem)
800{ 967{
801 int i; 968 int elem;
969 ULONGLONG idle, kernel, user;
970 time_t now = time (NULL);
971
972 /* Store another sample. We ignore samples that are less than 1 sec
973 apart. */
974 if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
975 {
976 sample_system_load (&idle, &kernel, &user);
977 last_idx = buf_next (last_idx);
978 samples[last_idx].sample_time = now;
979 samples[last_idx].idle = idle;
980 samples[last_idx].kernel = kernel;
981 samples[last_idx].user = user;
982 /* If the buffer has more that 15 min worth of samples, discard
983 the old ones. */
984 if (first_idx == -1)
985 first_idx = last_idx;
986 while (first_idx != last_idx
987 && (difftime (now, samples[first_idx].sample_time)
988 >= 15.0*60 + 2*DBL_EPSILON*now))
989 first_idx = buf_next (first_idx);
990 }
802 991
803 /* A faithful emulation is going to have to be saved for a rainy day. */ 992 for (elem = 0; elem < nelem; elem++)
804 for (i = 0; i < nelem; i++)
805 { 993 {
806 loadavg[i] = 0.0; 994 double avg = getavg (elem);
995
996 if (avg < 0)
997 break;
998 loadavg[elem] = avg;
807 } 999 }
808 return i; 1000
1001 return elem;
809} 1002}
810 1003
811/* Emulate getpwuid, getpwnam and others. */ 1004/* Emulate getpwuid, getpwnam and others. */
@@ -5693,6 +5886,9 @@ globals_of_w32 ()
5693 g_b_init_equal_sid = 0; 5886 g_b_init_equal_sid = 0;
5694 g_b_init_copy_sid = 0; 5887 g_b_init_copy_sid = 0;
5695 g_b_init_get_length_sid = 0; 5888 g_b_init_get_length_sid = 0;
5889 g_b_init_get_native_system_info = 0;
5890 g_b_init_get_system_times = 0;
5891 num_of_processors = 0;
5696 /* The following sets a handler for shutdown notifications for 5892 /* The following sets a handler for shutdown notifications for
5697 console apps. This actually applies to Emacs in both console and 5893 console apps. This actually applies to Emacs in both console and
5698 GUI modes, since we had to fool windows into thinking emacs is a 5894 GUI modes, since we had to fool windows into thinking emacs is a