fix cpu idle metric for windows NT and 2000

This commit is contained in:
Doug MacEachern 2004-11-02 23:17:18 +00:00
parent 9347442bad
commit b1acfcf5e9
2 changed files with 80 additions and 3 deletions

View File

@ -84,6 +84,19 @@ typedef DWORD (CALLBACK *LPGETUDPTABLE)(PMIB_UDPTABLE, PDWORD, BOOL);
typedef DWORD (CALLBACK *LPGETTCPEXTABLE)(PMIB_TCPEXTABLE *, BOOL, HANDLE,
DWORD, DWORD);
typedef DWORD (CALLBACK *LPSYSINFO)(DWORD, PVOID, ULONG, PULONG);
/* no longer in the standard header files */
typedef struct {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
#define SystemProcessorPerformanceInformation 8
typedef struct {
sigar_pid_t pid;
int ppid;
@ -105,11 +118,13 @@ struct sigar_t {
char *perfbuf;
DWORD perfbuf_size;
HINSTANCE ip_handle;
HINSTANCE nt_handle;
LPGETIFTABLE get_if_table;
LPGETIPFORWARDTABLE get_ipforward_table;
LPGETTCPTABLE get_tcp_table;
LPGETTCPEXTABLE get_tcpx_table;
LPGETUDPTABLE get_udp_table;
LPSYSINFO get_ntsys_info;
sigar_win32_pinfo_t pinfo;
WORD ws_version;
int ws_error;

View File

@ -179,13 +179,24 @@ int sigar_os_open(sigar_t **sigar)
"TcpExTableFromStack");
(*sigar)->get_udp_table =
(LPGETUDPTABLE)GetProcAddress(h, "GetUdpTable");
(*sigar)->ip_handle = h;
}
else {
(*sigar)->get_if_table = NULL;
(*sigar)->get_ipforward_table = NULL;
(*sigar)->ip_handle = NULL;
}
if ((h = LoadLibrary("Ntdll.dll"))) {
(*sigar)->get_ntsys_info =
(LPSYSINFO)GetProcAddress(h, "NtQuerySystemInformation");
(*sigar)->nt_handle = h;
}
else {
(*sigar)->get_ntsys_info = NULL;
(*sigar)->nt_handle = NULL;
}
(*sigar)->ip_handle = h;
(*sigar)->pinfo.pid = -1;
(*sigar)->ws_version = 0;
(*sigar)->ncpu = 0;
@ -208,6 +219,10 @@ int sigar_os_close(sigar_t *sigar)
FreeLibrary(sigar->ip_handle);
}
if (sigar->nt_handle) {
FreeLibrary(sigar->nt_handle);
}
if (sigar->ws_version != 0) {
WSACleanup();
}
@ -329,6 +344,53 @@ static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar,
return PdhFirstInstance(object);
}
static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu,
DWORD idx,
PERF_COUNTER_BLOCK *counter_block,
DWORD *perf_offsets)
{
cpu->idle = 0;
if (perf_offsets[PERF_IX_CPU_IDLE]) {
cpu->idle = PERF_VAL(PERF_IX_CPU_IDLE);
}
else {
/* windows NT and 2000 do not have an Idle counter */
sigar_cpu_count(sigar);
if (sigar->get_ntsys_info) {
DWORD retval, num;
/* XXX unhardcode 16 */
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[16];
sigar->get_ntsys_info(SystemProcessorPerformanceInformation,
&info, sizeof(info), &retval);
if (!retval) {
return GetLastError();
}
num = retval/sizeof(info[0]);
if (idx == -1) {
int i;
for (i=0; i<num; i++) {
cpu->idle += info[i].IdleTime.QuadPart;
}
}
else if (idx < num) {
cpu->idle = info[idx].IdleTime.QuadPart;
}
else {
return ERROR_INVALID_DATA;
}
}
else {
return ERROR_INVALID_FUNCTION;
}
}
return SIGAR_OK;
}
SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
{
PERF_INSTANCE_DEFINITION *inst;
@ -349,7 +411,7 @@ SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu)
cpu->sys = PERF_VAL(PERF_IX_CPU_SYS);
cpu->user = PERF_VAL(PERF_IX_CPU_USER);
cpu->idle = PERF_VAL(PERF_IX_CPU_IDLE);
get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets);
cpu->nice = 0; /* no nice here */
cpu->total = cpu->sys + cpu->user + cpu->idle;
@ -408,7 +470,7 @@ SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist)
cpu->sys += PERF_VAL(PERF_IX_CPU_SYS);
cpu->user += PERF_VAL(PERF_IX_CPU_USER);
cpu->idle += PERF_VAL(PERF_IX_CPU_IDLE);
get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets);
cpu->nice = 0; /* no nice here */
cpu->total += cpu->sys + cpu->user + cpu->idle;