diff options
| author | Eli Zaretskii | 2009-07-04 10:43:10 +0000 |
|---|---|---|
| committer | Eli Zaretskii | 2009-07-04 10:43:10 +0000 |
| commit | ad9e2d54dd85944547f1333a616098e92f114850 (patch) | |
| tree | 7b4dd9c2cb8a7cccf733c6dec15d91b6779c2ffe /src | |
| parent | 7df24305ed8d85172aaa9084ed5b3f7d8e354bba (diff) | |
| download | emacs-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/ChangeLog | 12 | ||||
| -rw-r--r-- | src/w32.c | 206 |
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 @@ | |||
| 1 | 2009-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 | |||
| 1 | 2009-07-03 Jason Rumney <jasonr@gnu.org> | 13 | 2009-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. |
| @@ -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; | |||
| 191 | static BOOL g_b_init_get_length_sid; | 192 | static BOOL g_b_init_get_length_sid; |
| 192 | static BOOL g_b_init_equal_sid; | 193 | static BOOL g_b_init_equal_sid; |
| 193 | static BOOL g_b_init_copy_sid; | 194 | static BOOL g_b_init_copy_sid; |
| 195 | static BOOL g_b_init_get_native_system_info; | ||
| 196 | static 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); |
| 294 | typedef DWORD (WINAPI * GetLengthSid_Proc) ( | 297 | typedef DWORD (WINAPI * GetLengthSid_Proc) ( |
| 295 | PSID pSid); | 298 | PSID pSid); |
| 299 | typedef void (WINAPI * GetNativeSystemInfo_Proc) ( | ||
| 300 | LPSYSTEM_INFO lpSystemInfo); | ||
| 301 | typedef 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 | ||
| 735 | void 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 | |||
| 755 | BOOL 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. */ |
| 728 | char * | 778 | char * |
| @@ -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 | |||
| 849 | struct 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. */ | ||
| 857 | static unsigned num_of_processors; | ||
| 858 | |||
| 859 | /* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */ | ||
| 860 | static struct load_sample samples[16*60]; | ||
| 861 | static int first_idx = -1, last_idx = -1; | ||
| 862 | static int max_idx = sizeof (samples) / sizeof (samples[0]); | ||
| 863 | |||
| 864 | static int | ||
| 865 | buf_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 | |||
| 875 | static int | ||
| 876 | buf_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 | |||
| 886 | static void | ||
| 887 | sample_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. */ | ||
| 933 | static double | ||
| 934 | getavg (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 | |||
| 798 | int | 965 | int |
| 799 | getloadavg (double loadavg[], int nelem) | 966 | getloadavg (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 |