Skip to content
This repository

win: implement cpu times #327

Closed
wants to merge 4 commits into from

3 participants

Brian White Ben Noordhuis Bert Belder
Brian White

On a related note (node), I wonder if it's better to use Number::New instead of Integer::New inside GetCPUInfo() in node_os.cc. That additional change will allow us to have more accurate (read: non-negative) values when cpu times get very very high, as double has higher precision than a 32-bit int.

Brian White

Any comments/suggestions/questions/corrections? It'd be great to see support for this (and #326 or something like it) implemented in time for node 0.8 if at all possible (I do not know what the estimates are for a node 0.8 release these days).

Ben Noordhuis

@piscisaureus: Review this PR. It LGTM at first glance.

src/win/util.c
@@ -45,6 +45,17 @@
45 45 */
46 46 #define MAX_TITLE_LENGTH 8192
47 47
  48 +#define SystemProcessorPerformanceInformation 8
1
Bert Belder Collaborator

Can you put SDK/DDK definitions in winapi.h?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/win/util.c
@@ -45,6 +45,17 @@
45 45 */
46 46 #define MAX_TITLE_LENGTH 8192
47 47
  48 +#define SystemProcessorPerformanceInformation 8
  49 +typedef struct {
  50 + LARGE_INTEGER IdleTime;
  51 + LARGE_INTEGER KernelTime;
  52 + LARGE_INTEGER UserTime;
  53 + LARGE_INTEGER DpcTime;
  54 + LARGE_INTEGER InterruptTime;
  55 + ULONG InterruptCount;
  56 +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
  57 +typedef LONG (WINAPI *PROCNTQSI)(UINT,PVOID,ULONG,PULONG);
  58 +PROCNTQSI NtQuerySystemInformation;
3
Bert Belder Collaborator

Do it like the rest of libuv: https://github.com/joyent/libuv/blob/d07f2466d0a10ab02db588374dd97c2edd54c7fc/src/win/winapi.c#L87.

You'll probably have to make sure that uv_init() is called, you could add a function uv__once_init for that. See https://github.com/joyent/libuv/blob/master/src/win/core.c#L98.

Brian White
mscdex added a note

Add a uv__once_init to core.c/uv.h and call that from util.c?

Bert Belder Collaborator

yep

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/win/util.c
((17 lines not shown))
409 424 if (!(*cpu_infos)) {
410 425 uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
411 426 }
412 427
413 428 *count = 0;
414 429
415   - for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
  430 + szSppi = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * ncpus;
  431 + sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*)malloc(szSppi);
  432 + if (!sppi) {
  433 + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  434 + }
  435 +
  436 + SecureZeroMemory(sppi, szSppi);
1
Bert Belder Collaborator

Why is memset not sufficient?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Bert Belder
Collaborator

Good job! I'd like move the NtQuerySystemInformation acquisition to winapi.c and winapi.h where it belongs. After that this patch can land.

include/uv.h
@@ -212,6 +212,11 @@
212 212
213 213
214 214 /*
  215 + * Ensures that uv is initialized.
  216 + */
  217 +UV_EXTERN void uv__once_init(void);
1
Bert Belder Collaborator

This is an internal api. It should go into src/win/internal.h and not be marked UV_EXPORT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Brian White

No luck with the Unicode version of the registry API, kept getting ERROR_FILE_NOT_FOUND. Switching to the ANSI version makes everything work as expected.

Bert Belder
Collaborator

You probably have to use widechar strings. Compare

HANDLE h = CreateFileA("myfile", ...)
HANDLE h = CreateFileW(L"myfile", ...)

Brian White

I tried that as well.

Bert Belder
Collaborator

@mscdex I want to land this. Are you going to fix this up or should I do it?

Brian White

Well, I got it to work, although it requires making uv_cpu_info_s's model a wchar_t*/uint16_t* instead of char*, which means we'd have to then change *nix's implementation to use 16-bit strings. Unless we want to convert the wchar_t* from the unicode registry call to char* (then we might as well use the ANSI version registry call in the first place)?

I've never seen unicode processor name strings.

Bert Belder piscisaureus closed this pull request from a commit
Bert Belder piscisaureus 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
1d64a36
Saúl Ibarra Corretgé saghul referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
9 src/win/core.c
@@ -95,13 +95,18 @@ static void uv_loop_init(uv_loop_t* loop) {
95 95
96 96 static void uv_default_loop_init(void) {
97 97 /* Initialize libuv itself first */
98   - uv_once(&uv_init_guard_, uv_init);
  98 + uv__once_init();
99 99
100 100 /* Initialize the main loop */
101 101 uv_loop_init(&uv_default_loop_);
102 102 }
103 103
104 104
  105 +void uv__once_init(void) {
  106 + uv_once(&uv_init_guard_, uv_init);
  107 +}
  108 +
  109 +
105 110 uv_loop_t* uv_default_loop(void) {
106 111 uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
107 112 return &uv_default_loop_;
@@ -112,7 +117,7 @@ uv_loop_t* uv_loop_new(void) {
112 117 uv_loop_t* loop;
113 118
114 119 /* Initialize libuv itself first */
115   - uv_once(&uv_init_guard_, uv_init);
  120 + uv__once_init();
116 121
117 122 loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
118 123
2  src/win/internal.h
@@ -225,6 +225,8 @@ void uv_prepare_invoke(uv_loop_t* loop);
225 225 void uv_check_invoke(uv_loop_t* loop);
226 226 void uv_idle_invoke(uv_loop_t* loop);
227 227
  228 +void uv__once_init();
  229 +
228 230
229 231 /*
230 232 * Async watcher
50 src/win/util.c
@@ -45,7 +45,6 @@
45 45 */
46 46 #define MAX_TITLE_LENGTH 8192
47 47
48   -
49 48 static char *process_title;
50 49 static uv_once_t uv_process_title_init_guard_ = UV_ONCE_INIT;
51 50 static CRITICAL_SECTION process_title_lock;
@@ -400,23 +399,42 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
400 399 DWORD cpu_brand_length = sizeof(cpu_brand);
401 400 SYSTEM_INFO system_info;
402 401 uv_cpu_info_t* cpu_info;
403   - unsigned int i;
  402 + PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION sppi;
  403 + unsigned int i, ncpus, retval, szSppi, r;
  404 +
  405 + uv__once_init();
404 406
405 407 GetSystemInfo(&system_info);
406 408
407   - *cpu_infos = (uv_cpu_info_t*)malloc(system_info.dwNumberOfProcessors *
408   - sizeof(uv_cpu_info_t));
  409 + ncpus = system_info.dwNumberOfProcessors;
  410 +
  411 + *cpu_infos = (uv_cpu_info_t*)malloc(ncpus * sizeof(uv_cpu_info_t));
409 412 if (!(*cpu_infos)) {
410 413 uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
411 414 }
412 415
413 416 *count = 0;
414 417
415   - for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
  418 + szSppi = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * ncpus;
  419 + sppi = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(szSppi);
  420 + if (!sppi) {
  421 + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
  422 + }
  423 +
  424 + memset(sppi, 0, szSppi);
  425 +
  426 + r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi,
  427 + szSppi, &retval);
  428 + if (r != ERROR_SUCCESS || retval != szSppi) {
  429 + err = uv__new_sys_error(GetLastError());
  430 + goto done;
  431 + }
  432 +
  433 + for (i = 0; i < ncpus; i++) {
416 434 _snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i);
417 435
418   - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE,
419   - &processor_key) != ERROR_SUCCESS) {
  436 + if ((r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE,
  437 + &processor_key)) != ERROR_SUCCESS) {
420 438 if (i == 0) {
421 439 err = uv__new_sys_error(GetLastError());
422 440 goto done;
@@ -425,14 +443,14 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
425 443 continue;
426 444 }
427 445
428   - if (RegQueryValueEx(processor_key, "~MHz", NULL, NULL,
  446 + if (RegQueryValueExA(processor_key, "~MHz", NULL, NULL,
429 447 (LPBYTE)&cpu_speed, &cpu_speed_length)
430 448 != ERROR_SUCCESS) {
431 449 err = uv__new_sys_error(GetLastError());
432 450 goto done;
433 451 }
434 452
435   - if (RegQueryValueEx(processor_key, "ProcessorNameString", NULL, NULL,
  453 + if (RegQueryValueExA(processor_key, "ProcessorNameString", NULL, NULL,
436 454 (LPBYTE)&cpu_brand, &cpu_brand_length)
437 455 != ERROR_SUCCESS) {
438 456 err = uv__new_sys_error(GetLastError());
@@ -441,15 +459,14 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
441 459
442 460 RegCloseKey(processor_key);
443 461 processor_key = NULL;
444   -
  462 +
445 463 cpu_info = &(*cpu_infos)[i];
446 464
447   - /* $TODO: find times on windows */
448   - cpu_info->cpu_times.user = 0;
  465 + cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
  466 + cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - sppi[i].IdleTime.QuadPart) / 10000;
  467 + cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
  468 + cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
449 469 cpu_info->cpu_times.nice = 0;
450   - cpu_info->cpu_times.sys = 0;
451   - cpu_info->cpu_times.idle = 0;
452   - cpu_info->cpu_times.irq = 0;
453 470
454 471 cpu_info->model = strdup(cpu_brand);
455 472 cpu_info->speed = cpu_speed;
@@ -463,6 +480,9 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
463 480 if (processor_key) {
464 481 RegCloseKey(processor_key);
465 482 }
  483 + if (sppi) {
  484 + free(sppi);
  485 + }
466 486
467 487 if (err.code != UV_OK) {
468 488 free(*cpu_infos);
8 src/win/winapi.c
@@ -30,6 +30,7 @@ sRtlNtStatusToDosError pRtlNtStatusToDosError;
30 30 sNtDeviceIoControlFile pNtDeviceIoControlFile;
31 31 sNtQueryInformationFile pNtQueryInformationFile;
32 32 sNtSetInformationFile pNtSetInformationFile;
  33 +sNtQuerySystemInformation pNtQuerySystemInformation;
33 34 sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
34 35 sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
35 36 sCreateSymbolicLinkW pCreateSymbolicLinkW;
@@ -79,6 +80,13 @@ void uv_winapi_init() {
79 80 uv_fatal_error(GetLastError(), "GetProcAddress");
80 81 }
81 82
  83 + pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
  84 + ntdll_module,
  85 + "NtQuerySystemInformation");
  86 + if (pNtQuerySystemInformation == NULL) {
  87 + uv_fatal_error(GetLastError(), "GetProcAddress");
  88 + }
  89 +
82 90 kernel32_module = GetModuleHandleA("kernel32.dll");
83 91 if (kernel32_module == NULL) {
84 92 uv_fatal_error(GetLastError(), "GetModuleHandleA");
20 src/win/winapi.h
@@ -4203,6 +4203,19 @@ typedef enum _FILE_INFORMATION_CLASS {
4203 4203 FileMaximumInformation
4204 4204 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
4205 4205
  4206 +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
  4207 + LARGE_INTEGER IdleTime;
  4208 + LARGE_INTEGER KernelTime;
  4209 + LARGE_INTEGER UserTime;
  4210 + LARGE_INTEGER DpcTime;
  4211 + LARGE_INTEGER InterruptTime;
  4212 + ULONG InterruptCount;
  4213 +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
  4214 +
  4215 +#ifndef SystemProcessorPerformanceInformation
  4216 +# define SystemProcessorPerformanceInformation 8
  4217 +#endif
  4218 +
4206 4219 #ifndef DEVICE_TYPE
4207 4220 # define DEVICE_TYPE DWORD
4208 4221 #endif
@@ -4319,6 +4332,12 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile)
4319 4332 ULONG Length,
4320 4333 FILE_INFORMATION_CLASS FileInformationClass);
4321 4334
  4335 +typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
  4336 + (UINT SystemInformationClass,
  4337 + PVOID SystemInformation,
  4338 + ULONG SystemInformationLength,
  4339 + PULONG ReturnLength);
  4340 +
4322 4341
4323 4342 /*
4324 4343 * Kernel32 headers
@@ -4395,6 +4414,7 @@ extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
4395 4414 extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
4396 4415 extern sNtQueryInformationFile pNtQueryInformationFile;
4397 4416 extern sNtSetInformationFile pNtSetInformationFile;
  4417 +extern sNtQuerySystemInformation pNtQuerySystemInformation;
4398 4418
4399 4419
4400 4420 /* Kernel32 function pointers */

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.