From 9685685419231b0a3f8a2e454e4c963564629332 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 19 Feb 2017 05:38:40 +0100
Subject: kernel32: Make K32GetPerformanceInfo faster.

---
 dlls/kernel32/cpu.c | 68 ++++++++++++++++++++---------------------------------
 server/process.c    | 18 ++++++++++++++
 server/protocol.def |  9 +++++++
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/dlls/kernel32/cpu.c b/dlls/kernel32/cpu.c
index 5fb806746a0..01cb469b8db 100644
--- a/dlls/kernel32/cpu.c
+++ b/dlls/kernel32/cpu.c
@@ -216,14 +216,8 @@ BOOL WINAPI IsProcessorFeaturePresent (
  */
 BOOL WINAPI K32GetPerformanceInfo(PPERFORMANCE_INFORMATION info, DWORD size)
 {
-    union
-    {
-        SYSTEM_PERFORMANCE_INFORMATION performance;
-        SYSTEM_PROCESS_INFORMATION process;
-        SYSTEM_BASIC_INFORMATION basic;
-    } *sysinfo;
-    SYSTEM_PROCESS_INFORMATION *spi;
-    DWORD process_info_size;
+    SYSTEM_PERFORMANCE_INFORMATION performance;
+    SYSTEM_BASIC_INFORMATION basic;
     NTSTATUS status;
 
     TRACE( "(%p, %d)\n", info, size );
@@ -237,53 +231,41 @@ BOOL WINAPI K32GetPerformanceInfo(PPERFORMANCE_INFORMATION info, DWORD size)
     memset( info, 0, sizeof(*info) );
     info->cb = sizeof(*info);
 
-    /* fields from SYSTEM_PROCESS_INFORMATION */
-    NtQuerySystemInformation( SystemProcessInformation, NULL, 0, &process_info_size );
-    for (;;)
+    SERVER_START_REQ( get_system_info )
     {
-        sysinfo = HeapAlloc( GetProcessHeap(), 0, max(process_info_size, sizeof(*sysinfo)) );
-        if (!sysinfo)
+        status = wine_server_call( req );
+        if (!status)
         {
-            SetLastError( ERROR_OUTOFMEMORY );
-            return FALSE;
+            info->ProcessCount = reply->processes;
+            info->HandleCount = reply->handles;
+            info->ThreadCount = reply->threads;
         }
-        status = NtQuerySystemInformation( SystemProcessInformation, &sysinfo->process,
-                                           process_info_size, &process_info_size );
-        if (!status) break;
-        if (status != STATUS_INFO_LENGTH_MISMATCH)
-            goto err;
-        HeapFree( GetProcessHeap(), 0, sysinfo );
-    }
-    for (spi = &sysinfo->process;; spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset))
-    {
-        info->ProcessCount++;
-        info->HandleCount += spi->HandleCount;
-        info->ThreadCount += spi->dwThreadCount;
-        if (spi->NextEntryOffset == 0) break;
     }
+    SERVER_END_REQ;
+
+    if (status) goto err;
 
     /* fields from SYSTEM_PERFORMANCE_INFORMATION */
-    status = NtQuerySystemInformation( SystemPerformanceInformation, &sysinfo->performance,
-                                       sizeof(sysinfo->performance), NULL );
+    status = NtQuerySystemInformation( SystemPerformanceInformation, &performance,
+                                       sizeof(performance), NULL );
     if (status) goto err;
-    info->CommitTotal        = sysinfo->performance.TotalCommittedPages;
-    info->CommitLimit        = sysinfo->performance.TotalCommitLimit;
-    info->CommitPeak         = sysinfo->performance.PeakCommitment;
-    info->PhysicalAvailable  = sysinfo->performance.AvailablePages;
-    info->KernelTotal        = sysinfo->performance.PagedPoolUsage +
-                               sysinfo->performance.NonPagedPoolUsage;
-    info->KernelPaged        = sysinfo->performance.PagedPoolUsage;
-    info->KernelNonpaged     = sysinfo->performance.NonPagedPoolUsage;
+    info->CommitTotal        = performance.TotalCommittedPages;
+    info->CommitLimit        = performance.TotalCommitLimit;
+    info->CommitPeak         = performance.PeakCommitment;
+    info->PhysicalAvailable  = performance.AvailablePages;
+    info->KernelTotal        = performance.PagedPoolUsage +
+                               performance.NonPagedPoolUsage;
+    info->KernelPaged        = performance.PagedPoolUsage;
+    info->KernelNonpaged     = performance.NonPagedPoolUsage;
 
     /* fields from SYSTEM_BASIC_INFORMATION */
-    status = NtQuerySystemInformation( SystemBasicInformation, &sysinfo->basic,
-                                       sizeof(sysinfo->basic), NULL );
+    status = NtQuerySystemInformation( SystemBasicInformation, &basic,
+                                       sizeof(basic), NULL );
     if (status) goto err;
-    info->PhysicalTotal = sysinfo->basic.MmNumberOfPhysicalPages;
-    info->PageSize      = sysinfo->basic.PageSize;
+    info->PhysicalTotal = basic.MmNumberOfPhysicalPages;
+    info->PageSize      = basic.PageSize;
 
 err:
-    HeapFree( GetProcessHeap(), 0, sysinfo );
     if (status)
     {
         SetLastError( RtlNtStatusToDosError( status ) );
diff --git a/server/process.c b/server/process.c
index eaf61eaea99..a59be6cfad7 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1754,3 +1754,21 @@ DECL_HANDLER(set_job_completion_port)
 
     release_object( job );
 }
+
+/* Retrieve process, thread and handle count */
+DECL_HANDLER(get_system_info)
+{
+    struct process *process;
+
+    reply->processes = 0;
+    reply->threads = 0;
+    reply->handles = 0;
+
+    LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
+    {
+        if (!process->running_threads) continue;
+        reply->processes++;
+        reply->threads += process->running_threads;
+        reply->handles += get_handle_table_count( process );
+    }
+}
diff --git a/server/protocol.def b/server/protocol.def
index c26b24edc5f..85137ab3b52 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3866,3 +3866,12 @@ struct handle_info
     obj_handle_t handle;          /* handle to the job */
     int          status;          /* process exit code */
 @END
+
+
+/* Return system information values */
+@REQ(get_system_info)
+@REPLY
+    unsigned int processes;   /* number of processes */
+    unsigned int threads;     /* number of threads */
+    unsigned int handles;     /* number of handles */
+@END
-- 
2.11.0

