windows: add support for cpu times to uv_cpu_info()

* Also cleans up the code and makes it use unicode APIs consistently.
* Credits go to Brian White for creating an earlier version of this
  patch.

Closes #327
This commit is contained in:
Bert Belder 2012-06-02 20:01:33 +02:00
parent 4252240e54
commit 1d64a36caa

View File

@ -47,7 +47,6 @@
*/
#define MAX_TITLE_LENGTH 8192
static char *process_title;
static uv_once_t uv_process_title_init_guard_ = UV_ONCE_INIT;
static CRITICAL_SECTION process_title_lock;
@ -488,81 +487,148 @@ uv_err_t uv_uptime(double* uptime) {
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
uv_err_t err;
char key[128];
HKEY processor_key = NULL;
DWORD cpu_speed = 0;
DWORD cpu_speed_length = sizeof(cpu_speed);
char cpu_brand[256];
DWORD cpu_brand_length = sizeof(cpu_brand);
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
DWORD sppi_size;
SYSTEM_INFO system_info;
DWORD cpu_count, i, r;
ULONG result_size;
size_t size;
uv_err_t err;
uv_cpu_info_t* cpu_info;
unsigned int i;
*cpu_infos = NULL;
*count = 0;
uv__once_init();
GetSystemInfo(&system_info);
cpu_count = system_info.dwNumberOfProcessors;
*cpu_infos = (uv_cpu_info_t*)malloc(system_info.dwNumberOfProcessors *
sizeof(uv_cpu_info_t));
if (!(*cpu_infos)) {
size = cpu_count * sizeof(uv_cpu_info_t);
*cpu_infos = (uv_cpu_info_t*) malloc(size);
if (*cpu_infos == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto out;
}
memset(*cpu_infos, 0, size);
sppi_size = sizeof(*sppi) * cpu_count;
sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size);
if (!sppi) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
*count = 0;
r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
sppi,
sppi_size,
&result_size);
if (r != ERROR_SUCCESS || result_size != sppi_size) {
err = uv__new_sys_error(GetLastError());
goto out;
}
for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
_snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i);
for (i = 0; i < cpu_count; i++) {
WCHAR key_name[128];
HKEY processor_key;
DWORD cpu_speed;
DWORD cpu_speed_size = sizeof(cpu_speed);
WCHAR cpu_brand[256];
DWORD cpu_brand_size = sizeof(cpu_brand);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE,
&processor_key) != ERROR_SUCCESS) {
if (i == 0) {
err = uv__new_sys_error(GetLastError());
goto done;
}
_snwprintf(key_name,
ARRAY_SIZE(key_name),
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
i);
continue;
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
key_name,
0,
KEY_QUERY_VALUE,
&processor_key);
if (r != ERROR_SUCCESS) {
err = uv__new_sys_error(GetLastError());
goto out;
}
if (RegQueryValueEx(processor_key, "~MHz", NULL, NULL,
(LPBYTE)&cpu_speed, &cpu_speed_length)
!= ERROR_SUCCESS) {
if (RegQueryValueExW(processor_key,
L"~MHz",
NULL, NULL,
(BYTE*) &cpu_speed,
&cpu_speed_size) != ERROR_SUCCESS) {
err = uv__new_sys_error(GetLastError());
goto done;
RegCloseKey(processor_key);
goto out;
}
if (RegQueryValueEx(processor_key, "ProcessorNameString", NULL, NULL,
(LPBYTE)&cpu_brand, &cpu_brand_length)
!= ERROR_SUCCESS) {
if (RegQueryValueExW(processor_key,
L"ProcessorNameString",
NULL, NULL,
(BYTE*) &cpu_brand,
&cpu_brand_size) != ERROR_SUCCESS) {
err = uv__new_sys_error(GetLastError());
goto done;
RegCloseKey(processor_key);
goto out;
}
RegCloseKey(processor_key);
processor_key = NULL;
cpu_info = &(*cpu_infos)[i];
/* $TODO: find times on windows */
cpu_info->cpu_times.user = 0;
cpu_info->cpu_times.nice = 0;
cpu_info->cpu_times.sys = 0;
cpu_info->cpu_times.idle = 0;
cpu_info->cpu_times.irq = 0;
cpu_info->model = strdup(cpu_brand);
cpu_info->speed = cpu_speed;
cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
sppi[i].IdleTime.QuadPart) / 10000;
cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
cpu_info->cpu_times.nice = 0;
size = uv_utf16_to_utf8(cpu_brand,
cpu_brand_size / sizeof(WCHAR),
NULL,
0);
if (size == 0) {
err = uv__new_sys_error(GetLastError());
goto out;
}
/* Allocate 1 extra byte for the null terminator. */
cpu_info->model = (char*) malloc(size + 1);
if (cpu_info->model == NULL) {
err = uv__new_artificial_error(UV_ENOMEM);
goto out;
}
if (uv_utf16_to_utf8(cpu_brand,
cpu_brand_size / sizeof(WCHAR),
cpu_info->model,
size) == 0) {
err = uv__new_sys_error(GetLastError());
goto out;
}
/* Ensure that cpu_info->model is null terminated. */
cpu_info->model[size] = '\0';
(*count)++;
}
err = uv_ok_;
done:
if (processor_key) {
RegCloseKey(processor_key);
out:
if (sppi) {
free(sppi);
}
if (err.code != UV_OK) {
if (err.code != UV_OK &&
*cpu_infos != NULL) {
int i;
for (i = 0; i < *count; i++) {
/* This is safe because the cpu_infos memory area is zeroed out */
/* immediately after allocating it. */
free((*cpu_infos)[i].model);
}
free(*cpu_infos);
*cpu_infos = NULL;
*count = 0;
}