diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h index 1234567..abcdefg 100644 --- a/src/include/utils/pg_rusage.h +++ b/src/include/utils/pg_rusage.h @@ -15,10 +15,31 @@ #include +#ifdef WIN32 +typedef struct PgWin32ResourceUsage +{ + uint64 io_read_bytes; + uint64 io_write_bytes; + uint64 io_other_bytes; + uint32 io_read_ops; + uint32 io_write_ops; + size_t working_set_size; + size_t peak_working_set_size; + size_t private_bytes; + uint32 page_fault_count; + uint32 handle_count; + uint32 thread_count; +} PgWin32ResourceUsage; +#endif typedef struct PGRUsage { struct rusage ru; struct timeval tv; +#ifdef WIN32 + PgWin32ResourceUsage win32; +#endif } PGRUsage; diff --git a/src/backend/utils/misc/pg_rusage.c b/src/backend/utils/misc/pg_rusage.c index 2345678..bcdefgh 100644 --- a/src/backend/utils/misc/pg_rusage.c +++ b/src/backend/utils/misc/pg_rusage.c @@ -18,6 +18,12 @@ #include "utils/pg_rusage.h" +#ifdef WIN32 +#include +#include +#include +#endif + /* * Initialize usage snapshot. @@ -26,8 +32,87 @@ void pg_rusage_init(PGRUsage *ru0) { getrusage(RUSAGE_SELF, &ru0->ru); gettimeofday(&ru0->tv, NULL); + +#ifdef WIN32 + { + HANDLE hProcess = GetCurrentProcess(); + PROCESS_MEMORY_COUNTERS_EX memCounters; + IO_COUNTERS ioCounters; + + memset(&ru0->win32, 0, sizeof(PgWin32ResourceUsage)); + + /* Get memory statistics */ + memset(&memCounters, 0, sizeof(memCounters)); + memCounters.cb = sizeof(memCounters); + if (GetProcessMemoryInfo(hProcess, + (PROCESS_MEMORY_COUNTERS *)&memCounters, + sizeof(memCounters))) + { + ru0->win32.working_set_size = memCounters.WorkingSetSize; + ru0->win32.peak_working_set_size = memCounters.PeakWorkingSetSize; + ru0->win32.private_bytes = memCounters.PrivateUsage; + ru0->win32.page_fault_count = memCounters.PageFaultCount; + } + + /* Get I/O statistics */ + memset(&ioCounters, 0, sizeof(ioCounters)); + if (GetProcessIoCounters(hProcess, &ioCounters)) + { + ru0->win32.io_read_bytes = ioCounters.ReadTransferCount; + ru0->win32.io_write_bytes = ioCounters.WriteTransferCount; + ru0->win32.io_other_bytes = ioCounters.OtherTransferCount; + ru0->win32.io_read_ops = (uint32)ioCounters.ReadOperationCount; + ru0->win32.io_write_ops = (uint32)ioCounters.WriteOperationCount; + } + + /* Get handle count */ + GetProcessHandleCount(hProcess, &ru0->win32.handle_count); + + /* Get thread count using toolhelp32 snapshot */ + { + HANDLE hSnapshot; + THREADENTRY32 te32; + DWORD dwOwnerPID = GetCurrentProcessId(); + + ru0->win32.thread_count = 0; + + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hSnapshot != INVALID_HANDLE_VALUE) + { + te32.dwSize = sizeof(THREADENTRY32); + + if (Thread32First(hSnapshot, &te32)) + { + do + { + if (te32.th32OwnerProcessID == dwOwnerPID) + ru0->win32.thread_count++; + } while (Thread32Next(hSnapshot, &te32)); + } + CloseHandle(hSnapshot); + } + } + } +#endif } /* @@ -83,6 +168,26 @@ pg_rusage_show(const PGRUsage *ru0) (long) (r.ru_oublock - ru0->ru.ru_oublock)); appendStringInfo(&str, _("!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n"), r.ru_nvcsw - ru0->ru.ru_nvcsw, r.ru_nivcsw - ru0->ru.ru_nivcsw, r.ru_nvcsw, r.ru_nivcsw); + +#ifdef WIN32 + /* Show Windows-specific extended statistics */ + appendStringInfo(&str, _("!\tWindows: %zu KB working set (%zu KB peak), %zu KB private\n"), + r_win32.working_set_size / 1024, + r_win32.peak_working_set_size / 1024, + r_win32.private_bytes / 1024); + + appendStringInfo(&str, _("!\tI/O: %llu bytes read (%u ops), %llu write (%u ops), %llu other\n"), + (unsigned long long)(r_win32.io_read_bytes - ru0->win32.io_read_bytes), + r_win32.io_read_ops - ru0->win32.io_read_ops, + (unsigned long long)(r_win32.io_write_bytes - ru0->win32.io_write_bytes), + r_win32.io_write_ops - ru0->win32.io_write_ops, + (unsigned long long)(r_win32.io_other_bytes - ru0->win32.io_other_bytes)); + + appendStringInfo(&str, _("!\tResources: %u handles, %u threads, %u page faults\n"), + r_win32.handle_count, + r_win32.thread_count, + r_win32.page_fault_count - ru0->win32.page_fault_count); +#endif return str.data; } diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile index 3456789..cdefghi 100644 --- a/src/backend/utils/misc/Makefile +++ b/src/backend/utils/misc/Makefile @@ -8,3 +8,7 @@ include $(top_builddir)/src/Makefile.global OBJS = \ guc.o \ pg_rusage.o + +ifeq ($(PORTNAME), win32) +LIBS += -lpsapi +endif