dockapps/wmcpuload/src/cpu_cygwin.c
2016-10-20 15:34:31 +01:00

218 lines
5.4 KiB
C

/*
* cpu_cygwin.c - module to get cpu usage, for Cygwin
*
* Copyright (c) 2001 Seiichi SATO <ssato@sh.rim.or.jp>
*
* licensed under the GPL
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "cpu.h"
#include <w32api/windows.h>
#include <w32api/windef.h>
#include <w32api/winreg.h>
#include <w32api/winbase.h>
#define WIN32_9x 1 /* 95, 98, Me */
#define WIN32_NT 2 /* NT, 2000, XP */
/* NT, 2000, XP */
#define LONGINT2DOUBLE(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart))
/*
* The following both data structures aren't defined anywhere in the Microsoft
* header files. Taken from DNA's libraly licensed under GPL.
* (http://estu.nit.ac.jp/~e982457/freesoft/freesoft.html)
*/
typedef struct _SYSTEM_BASIC_INFORMATION { /* Info Class 0 */
DWORD unused1;
ULONG unused2[6];
PVOID unused3[2];
ULONG unused4;
BYTE bKeNumberProcessors;
BYTE unused5;
WORD unused6;
} SYSTEM_BASIC_INFORMATION;
typedef struct _SYSTEM_PERFORMANCE_INFORMATION { /* Info Class 2 */
LARGE_INTEGER IdleTime;
DWORD unused[76];
} SYSTEM_PERFORMANCE_INFORMATION;
typedef struct _SYSTEM_TIME_INFORMATION { /* Info Class 3 */
LARGE_INTEGER liKeBootTime;
LARGE_INTEGER liKeSystemTime;
LARGE_INTEGER liExpTimeZoneBias;
ULONG uCurrentTimeZoneId;
DWORD dwReserved;
} SYSTEM_TIME_INFORMATION;
#define SystemBasicInformation 0
#define SystemPerformanceInformation 2
#define SystemTimeInformation 3
/* end of NT, 2000, XP */
static int platform = 0;
void
cpu_init(void)
{
OSVERSIONINFO os_ver_info;
/* which version? */
os_ver_info.dwOSVersionInfoSize = sizeof(os_ver_info);
GetVersionEx(&os_ver_info);
platform = os_ver_info.dwPlatformId;
if ((platform != WIN32_9x) && (platform != WIN32_NT)) {
fprintf(stderr, "%s: unknown platform\n", PACKAGE);
exit (1);
}
}
/*
* cpu_get_usage_9x(): get cpu usage in percent via registry
*
* How to get:
* 1. query 'PerfStats.StartStat.KERNEL.CPUUsage' to start monitoring
* 2. get usage from 'PerfStats.StatData.KERNEL.CPUUsage'
* 3. query 'PerfStats.StopStat.KERNEL.CPUUsage' to stop monitoring
*
* If cpu usage is 100% evry time, please reboot.;(
*/
static int
cpu_get_usage_9x(cpu_options *opts)
{
int usage = 0;
HKEY hkeys; /* for monitoring (start, stop) */
HKEY hkeyr; /* for reading usage */
DWORD dummy;
DWORD dwsize = sizeof(DWORD);
if (RegOpenKeyEx(HKEY_DYN_DATA, "PerfStats\\StatData",
0, KEY_READ, &hkeyr) != ERROR_SUCCESS) {
fprintf(stderr, "%s: could not open registry 'PerfStats\\StatData'\n", PACKAGE);
return 0;
}
/* start monitoring */
RegOpenKeyEx(HKEY_DYN_DATA, "PerfStats\\StartStat", 0, KEY_READ, &hkeys);
RegQueryValueEx(hkeys, "KERNEL\\CPUUsage", 0, NULL, (LPBYTE)&dummy,
&dwsize);
RegCloseKey(hkeys);
/* get usage */
RegQueryValueEx(hkeyr, "KERNEL\\CPUUsage", 0, NULL, (LPBYTE)&usage,
&dwsize);
RegCloseKey(hkeyr);
/* stop monitoring */
RegOpenKeyEx(HKEY_DYN_DATA, "PerfStats\\StopStat", 0, KEY_READ, &hkeys);
RegQueryValueEx(hkeys, "KERNEL\\CPUUsage", 0, NULL, (LPBYTE)&dummy,
&dwsize);
RegCloseKey(hkeys);
return usage;
}
/*
* cpu_get_usage_NT:
*
* How to get:
* 1. Load NTDLL.DLL (should use dlopen?)
* 2. Get addresses of NtQuerySystemInformation (should use dlsym?)
* 3. Get system time and idle time
* 4. Calculate cpu usage
* 5. Unload NTDLL.DLL (should use dlclose?)
*
* I do not test this function with SMP system, since I do not have SMP system.
*/
static int
cpu_get_usage_NT(cpu_options *opts)
{
int usage;
double total, used;
static double pre_total = 0, pre_used = 0;
HINSTANCE h_ntdll;
FARPROC NtQuerySystemInformation = NULL;
SYSTEM_BASIC_INFORMATION sbi;
SYSTEM_TIME_INFORMATION sti;
SYSTEM_PERFORMANCE_INFORMATION spi;
if ((h_ntdll = LoadLibraryEx("NTDLL.DLL", NULL, 0)) == NULL) {
fprintf(stderr, "%s: could not load NTDLL.DLL\n", PACKAGE);
exit (1);
}
NtQuerySystemInformation = GetProcAddress(h_ntdll,
"NtQuerySystemInformation");
if (!NtQuerySystemInformation) {
fprintf(stderr, "%s: could not find NtQuerySystemInformation()\n", PACKAGE);
FreeLibrary(h_ntdll);
return 0;
}
if ((NtQuerySystemInformation(SystemBasicInformation,
&sbi,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL)) != NO_ERROR)
return 0;
if ((NtQuerySystemInformation(SystemTimeInformation,
&sti,
sizeof(SYSTEM_TIME_INFORMATION),
0)) != NO_ERROR)
return 0;
if ((NtQuerySystemInformation(SystemPerformanceInformation,
&spi,
sizeof(SYSTEM_PERFORMANCE_INFORMATION),
0)) != NO_ERROR)
return 0;
total = LONGINT2DOUBLE(sti.liKeSystemTime);
used = total - LONGINT2DOUBLE(spi.IdleTime);
if ((pre_total == 0) || !(total - pre_total > 0)) {
usage = 0;
} else {
usage = (100 * (used - pre_used)) / (total - pre_total);
}
if (sbi.bKeNumberProcessors > 1) {
usage = usage / sbi.bKeNumberProcessors;
}
pre_used = used;
pre_total = total;
FreeLibrary(h_ntdll);
return usage;
}
/* return current cpu usage in percent */
int
cpu_get_usage(cpu_options *opts)
{
switch (platform) {
case WIN32_9x:
return cpu_get_usage_9x(opts);
case WIN32_NT:
return cpu_get_usage_NT(opts);
default: /* make gcc happy */
break;
}
return 0;
}