From a226f6609f6fcec61331cbe4b47c9bc4e5f56d62 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Fri, 17 Oct 2008 15:25:30 -0500 Subject: [PATCH] ntdll: Implement SystemProcessorPerformanceInformation for Linux (/proc filesystems) and Mac OS X. --- dlls/ntdll/nt.c | 120 ++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/tests/info.c | 20 ++++++- 2 files changed, 134 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c index 3ca17555dbf..a8365dc9c95 100644 --- a/dlls/ntdll/nt.c +++ b/dlls/ntdll/nt.c @@ -37,6 +37,12 @@ #include "ntdll_misc.h" #include "wine/server.h" +#ifdef __APPLE__ +#include +#include +#include +#endif + WINE_DEFAULT_DEBUG_CHANNEL(ntdll); /* @@ -900,18 +906,122 @@ NTSTATUS WINAPI NtQuerySystemInformation( break; case SystemProcessorPerformanceInformation: { - SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION sppi; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL; + unsigned int cpus = 0; + int out_cpus = Length / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); - memset(&sppi, 0 , sizeof(sppi)); /* FIXME */ - len = sizeof(sppi); + if (out_cpus == 0) + { + len = 0; + ret = STATUS_INFO_LENGTH_MISMATCH; + break; + } + else +#ifdef __APPLE__ + { + processor_cpu_load_info_data_t *pinfo; + mach_msg_type_number_t info_count; + + if (host_processor_info (mach_host_self (), + PROCESSOR_CPU_LOAD_INFO, + &cpus, + (processor_info_array_t*)&pinfo, + &info_count) == 0) + { + int i; + cpus = min(cpus,out_cpus); + len = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * cpus; + sppi = RtlAllocateHeap(GetProcessHeap(), 0,len); + for (i = 0; i < cpus; i++) + { + sppi[i].liIdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE]; + sppi[i].liKernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM]; + sppi[i].liUserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER]; + } + vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count); + } + } +#else + { + FILE *cpuinfo = fopen("/proc/stat","r"); + if (cpuinfo) + { + unsigned usr,nice,sys; + unsigned long idle; + int count; + char name[10]; + + /* first line is combined usage */ + count = fscanf(cpuinfo,"%s %u %u %u %lu",name, &usr, &nice, + &sys, &idle); + /* we set this up in the for older non-smp enabled kernels */ + if (count == 5 && strcmp(name,"cpu")==0) + { + sppi = RtlAllocateHeap(GetProcessHeap(), 0, + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + sppi->liIdleTime.QuadPart = idle; + sppi->liKernelTime.QuadPart = sys; + sppi->liUserTime.QuadPart = usr; + cpus = 1; + len = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); + } + + do + { + count = fscanf(cpuinfo,"%s %u %u %u %lu",name, &usr, + &nice, &sys, &idle); + if (count == 5 && strncmp(name,"cpu",3)==0) + { + out_cpus --; + if (name[3]=='0') /* first cpu */ + { + sppi->liIdleTime.QuadPart = idle; + sppi->liKernelTime.QuadPart = sys; + sppi->liUserTime.QuadPart = usr; + } + else /* new cpu */ + { + len = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * (cpus+1); + sppi = RtlReAllocateHeap(GetProcessHeap(), 0, sppi, len); + sppi[cpus].liIdleTime.QuadPart = idle; + sppi[cpus].liKernelTime.QuadPart = sys; + sppi[cpus].liUserTime.QuadPart = usr; + cpus++; + } + } + else + break; + } while (out_cpus > 0); + fclose(cpuinfo); + } + } +#endif + + if (cpus == 0) + { + static int i = 1; + + sppi = RtlAllocateHeap(GetProcessHeap(),0,sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + + memset(sppi, 0 , sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n"); + + /* many programs expect these values to change so fake change */ + len = sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); + sppi->liKernelTime.QuadPart = 1 * i; + sppi->liUserTime.QuadPart = 2 * i; + sppi->liIdleTime.QuadPart = 3 * i; + i++; + } if (Length >= len) { if (!SystemInformation) ret = STATUS_ACCESS_VIOLATION; - else memcpy( SystemInformation, &sppi, len); + else memcpy( SystemInformation, sppi, len); } else ret = STATUS_INFO_LENGTH_MISMATCH; - FIXME("info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n"); + + RtlFreeHeap(GetProcessHeap(),0,sppi); } break; case SystemModuleInformation: diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 74f180e29d8..d93e0bc6866 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -344,23 +344,41 @@ static void test_query_procperf(void) ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); /* Try it for 1 processor */ + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION), &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) == ReturnLength, "Inconsistent length %d\n", ReturnLength); - + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); + /* Try it for all processors */ + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength, &ReturnLength); ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); /* A too large given buffer size */ sppi = HeapReAlloc(GetProcessHeap(), 0, sppi , NeededLength + 2); + sppi->KernelTime.QuadPart = 0xdeaddead; + sppi->UserTime.QuadPart = 0xdeaddead; + sppi->IdleTime.QuadPart = 0xdeaddead; status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi, NeededLength + 2, &ReturnLength); ok( status == STATUS_SUCCESS || status == STATUS_INFO_LENGTH_MISMATCH /* vista */, "Expected STATUS_SUCCESS or STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status); ok( NeededLength == ReturnLength, "Inconsistent length (%d) <-> (%d)\n", NeededLength, ReturnLength); + ok (sppi->KernelTime.QuadPart != 0xdeaddead, "KernelTime unchanged\n"); + ok (sppi->UserTime.QuadPart != 0xdeaddead, "UserTime unchanged\n"); + ok (sppi->IdleTime.QuadPart != 0xdeaddead, "IdleTime unchanged\n"); HeapFree( GetProcessHeap(), 0, sppi); }