From b1acfcf5e929d67cc4503dd3cf0e048a6f8b6966 Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Tue, 2 Nov 2004 23:17:18 +0000 Subject: [PATCH] fix cpu idle metric for windows NT and 2000 --- src/os/win32/sigar_os.h | 15 +++++++++ src/os/win32/win32_sigar.c | 68 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/os/win32/sigar_os.h b/src/os/win32/sigar_os.h index 0d9ed295..c66ad2c6 100644 --- a/src/os/win32/sigar_os.h +++ b/src/os/win32/sigar_os.h @@ -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; diff --git a/src/os/win32/win32_sigar.c b/src/os/win32/win32_sigar.c index 60f13938..00ebe4f2 100644 --- a/src/os/win32/win32_sigar.c +++ b/src/os/win32/win32_sigar.c @@ -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; iidle += 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;