[PATCH] Cygwin: proc: Cache system process information

Takashi Yano takashi.yano@nifty.ne.jp
Fri Sep 4 03:58:56 GMT 2026


If a process reads /proc/<pid>/stat for multiple PIDs, current code
every time calls NtQuerySystemInformation(SystemProcessInformation).
In addition, the buffer size is estimated by calling that function
with increasing buffer size. This takes 15 - 20 msec. This is looks
short time, however it is not negligible in some situation. If the
number of the process is 100, reading /proc/<pid>/stat takes 1.5 -
2.0 sec. Due to this behaviour, process pane of the btop is very
heavy.

With this patch, system process information is cached per process
for a short time (20 msec) to improve efficiency. Also, the buffer
size needed by NtQuerySystemInformation() is stored in static area,
so that the number of function call is reduced (~1/7). As a result,
the process pane of btop becomes significantly light (takes only
~15 msec for 100 processes).

Signef-off-by: Takashi Yano <takashi.yano@nift.ne.jp>
Reviewed-by:
---
 winsup/cygwin/fhandler/process.cc | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc
index 537a4b370..97f3e0a2f 100644
--- a/winsup/cygwin/fhandler/process.cc
+++ b/winsup/cygwin/fhandler/process.cc
@@ -1524,14 +1524,30 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
 {
   /* This isn't really heavy magic - just go through the processes' threads
      one by one and return a value accordingly.  Errors are silently ignored. */
+  const ULONGLONG cache_time = 20;
+  static NO_COPY muto cache_guard;
   NTSTATUS status;
-  PSYSTEM_PROCESS_INFORMATION p, sp;
-  ULONG n = 0x4000;
+  static PSYSTEM_PROCESS_INFORMATION p = NULL;
+  static ULONGLONG t0 = 0;
+  PSYSTEM_PROCESS_INFORMATION sp;
+  static ULONG last_n = 0x4000;
+  ULONG n;
   int state =' ';
 
+  cache_guard.init ("get_process_state")->acquire ();
+  n = last_n;
+
+  if (GetTickCount64 () - t0 < cache_time && p)
+    goto reuse_query;
+  else if (p)
+    {
+      free (p);
+      p = NULL;
+    }
+
   p = (PSYSTEM_PROCESS_INFORMATION) malloc (n);
   if (!p)
-    return state;
+    goto out;
   while (true)
     {
       status = NtQuerySystemInformation (SystemProcessInformation,
@@ -1550,6 +1566,9 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
 		    status, RtlNtStatusToDosError (status));
       goto out;
     }
+  last_n = n;
+  t0 = GetTickCount64 ();
+reuse_query:
   state = 'Z';
   sp = p;
   for (;;)
@@ -1579,7 +1598,7 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
       sp = (PSYSTEM_PROCESS_INFORMATION) ((char *) sp + sp->NextEntryOffset);
     }
 out:
-  free (p);
+  cache_guard.release ();
   return state;
 }
 
-- 
2.51.0



More information about the Cygwin-patches mailing list