Skip to content

Instantly share code, notes, and snippets.

@gavz
Forked from AndreyBazhan/ws.cpp
Created March 17, 2025 22:06
Show Gist options
  • Save gavz/9d6300d747638d9a41377cd3688401c5 to your computer and use it in GitHub Desktop.
Save gavz/9d6300d747638d9a41377cd3688401c5 to your computer and use it in GitHub Desktop.
Process Explorer: Process Properties->Performance tab performance issue
#include <Windows.h>
#include <psapi.h>
int main()
{
HANDLE ProcessHandle;
ULONG Processes[4096];
ULONG DataSize;
ULONG NumberOfProcesses;
ULONG i;
for ( ; ; ) {
if (!EnumProcesses(Processes, sizeof(Processes), &DataSize)) {
return 1;
}
NumberOfProcesses = DataSize / sizeof(ULONG);
for (i = 0; i < NumberOfProcesses; i++) {
ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
Processes[i]);
if (ProcessHandle) {
PSAPI_WORKING_SET_INFORMATION WorkingSetInformation;
PPSAPI_WORKING_SET_INFORMATION Buffer = NULL;
ULONG BufferSize = 0;
ULONG LastError;
BOOL IsOk;
#if 1
//
// This is the current approach to get working set information in Process Explorer v16.22 in Process Properties dialog.
// For a process with working set 10 GB it takes 1281 ((((10 * 1024 * 1024 * 1024) / 4096) * 8 + 8) / 16384 + 1) loops to get working set information.
// Note that in main window it uses allocated buffer from the first process query and if the process's working set were increased it will add 0x4000
// to the current buffer size, so the issue is slightly mitigated.
//
for ( ; ; ) {
IsOk = QueryWorkingSet(ProcessHandle, Buffer, BufferSize);
if (IsOk && Buffer && ((((ULONG)Buffer->NumberOfEntries * RTL_FIELD_SIZE(PSAPI_WORKING_SET_INFORMATION, NumberOfEntries)) + FIELD_OFFSET(PSAPI_WORKING_SET_INFORMATION, WorkingSetInfo)) <= BufferSize)) {
break;
}
if (Buffer) {
HeapFree(GetProcessHeap(), 0, Buffer);
Buffer = NULL;
}
LastError = GetLastError();
if (LastError != ERROR_BAD_LENGTH) {
break;
}
BufferSize += 0x4000;
Buffer = (PPSAPI_WORKING_SET_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
}
#else
//
// This is the approach with one loop.
//
for ( ; ; ) {
Buffer = &WorkingSetInformation;
BufferSize = sizeof(WorkingSetInformation);
IsOk = QueryWorkingSet(ProcessHandle, Buffer, BufferSize);
if (IsOk) {
break;
}
LastError = GetLastError();
if (LastError != ERROR_BAD_LENGTH) {
break;
}
if (!Buffer->NumberOfEntries) {
break;
}
BufferSize = ((ULONG)Buffer->NumberOfEntries * RTL_FIELD_SIZE(PSAPI_WORKING_SET_INFORMATION, NumberOfEntries)) + FIELD_OFFSET(PSAPI_WORKING_SET_INFORMATION, WorkingSetInfo);
Buffer = (PPSAPI_WORKING_SET_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
if (Buffer) {
IsOk = QueryWorkingSet(ProcessHandle, Buffer, BufferSize);
if (IsOk) {
break;
}
else {
HeapFree(GetProcessHeap(), 0, Buffer);
Buffer = NULL;
}
}
}
#endif
if (Buffer && (Buffer != &WorkingSetInformation)) {
HeapFree(GetProcessHeap(), 0, Buffer);
Buffer = NULL;
}
CloseHandle(ProcessHandle);
}
}
Sleep(1000);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment