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.
This commit is contained in:
parent
7df24305ed
commit
ad9e2d54dd
2 changed files with 213 additions and 5 deletions
|
@ -1,3 +1,15 @@
|
|||
2009-07-04 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
Emulation of `getloadavg' on MS-Windows.
|
||||
* w32.c: 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.
|
||||
|
||||
2009-07-03 Jason Rumney <jasonr@gnu.org>
|
||||
|
||||
* w32term.c (w32_initialize): Use standard types.
|
||||
|
|
206
src/w32.c
206
src/w32.c
|
@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|||
#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_global_memory_status_ex;
|
|||
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 @@ typedef BOOL (WINAPI * EqualSid_Proc) (
|
|||
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 @@ BOOL WINAPI copy_sid (
|
|||
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 @@ gethostname (char *buffer, int size)
|
|||
#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);
|
||||
|
||||
/* A faithful emulation is going to have to be saved for a rainy day. */
|
||||
for (i = 0; i < nelem; i++)
|
||||
/* 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)
|
||||
{
|
||||
loadavg[i] = 0.0;
|
||||
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);
|
||||
}
|
||||
return i;
|
||||
|
||||
for (elem = 0; elem < nelem; elem++)
|
||||
{
|
||||
double avg = getavg (elem);
|
||||
|
||||
if (avg < 0)
|
||||
break;
|
||||
loadavg[elem] = avg;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
/* Emulate getpwuid, getpwnam and others. */
|
||||
|
@ -5693,6 +5886,9 @@ globals_of_w32 ()
|
|||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue