[newlib-cygwin] Cygwin: proc: Cache system process information
Takashi Yano
tyan0@sourceware.org
Mon Sep 7 11:47:30 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=dae171e433cd381e9b3ac48c1d2716b8168c9241
commit dae171e433cd381e9b3ac48c1d2716b8168c9241
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date: Fri Sep 4 12:40:02 2026 +0900
Cygwin: proc: Cache system process information
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 looks
short time, however it is not negligible in some situation. If the
number of processes 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. The buffer is
allocated first time when the corresponding /proc file system is
read, and held until process exits. If the buffer size needed by
NtQuerySystemInformation() is increased, the buffer will be re-
allocated, however never freed. The buffer pointer and the buffer
size are stored in the static area, so that the number of the
function call is reduced much. As a result, the process pane of
btop becomes significantly light. It takes only ~15 msec for 100
processes.
Fixes: 9ba913a56dd6 ("* fhandler_process.cc (process_listing): Add 'stat' and 'statm'.")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Mark Geisert <mark@maxrnd.com>
Diff:
---
winsup/cygwin/fhandler/process.cc | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc
index 537a4b370..404668661 100644
--- a/winsup/cygwin/fhandler/process.cc
+++ b/winsup/cygwin/fhandler/process.cc
@@ -1524,14 +1524,24 @@ 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 n = 0x4000;
int state =' ';
- p = (PSYSTEM_PROCESS_INFORMATION) malloc (n);
+ cache_guard.init ("get_process_state")->acquire ();
+
+ if (GetTickCount64 () - t0 < cache_time && p)
+ goto reuse_query;
+
+ if (!p)
+ p = (PSYSTEM_PROCESS_INFORMATION) malloc (n);
if (!p)
- return state;
+ goto out;
while (true)
{
status = NtQuerySystemInformation (SystemProcessInformation,
@@ -1550,6 +1560,8 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
status, RtlNtStatusToDosError (status));
goto out;
}
+ t0 = GetTickCount64 ();
+reuse_query:
state = 'Z';
sp = p;
for (;;)
@@ -1579,7 +1591,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;
}
More information about the Cygwin-cvs
mailing list