Created
May 5, 2021 17:06
-
-
Save msmania/b4585a7979516e4d7473cab57f586609 to your computer and use it in GitHub Desktop.
Getting page file info in various ways
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#include <windows.h> | |
#include <intrin.h> | |
#include <pdh.h> | |
#include <pdhmsg.h> | |
#include <psapi.h> | |
#include <strsafe.h> | |
void Log(LPCWSTR format, ...) { | |
wchar_t linebuf[1024]; | |
va_list v; | |
va_start(v, format); | |
::StringCbVPrintfW(linebuf, sizeof(linebuf), format, v); | |
vwprintf(format, v); | |
va_end(v); | |
} | |
class QPC { | |
int64_t t_, to_msec_; | |
static int64_t Now() { | |
LARGE_INTEGER t; | |
::QueryPerformanceCounter(&t); | |
return t.QuadPart; | |
} | |
public: | |
QPC() : t_(0) { | |
LARGE_INTEGER x; | |
::QueryPerformanceFrequency(&x); | |
to_msec_ = x.QuadPart / 1000; | |
} | |
void Reset() { | |
t_ = Now(); | |
_mm_mfence(); | |
} | |
int64_t Tick() const { | |
_mm_mfence(); | |
return Now() - t_; | |
} | |
double MSec() const { | |
_mm_mfence(); | |
return static_cast<double>(Now() - t_) / to_msec_; | |
} | |
}; | |
const HANDLE kCurrentProcess = reinterpret_cast<HANDLE>(-1); | |
enum PROCESSINFOCLASS { | |
ProcessBasicInformation = 0, | |
ProcessQuotaLimits = 1, | |
ProcessVmCounters = 3, | |
}; | |
enum SYSTEM_INFORMATION_CLASS { | |
SystemMemoryUsageInformation = 0xb6, | |
}; | |
extern "C" LONG WINAPI NtQueryInformationProcess( | |
HANDLE ProcessHandle, | |
PROCESSINFOCLASS ProcessInformationClass, | |
PVOID ProcessInformation, | |
ULONG ProcessInformationLength, | |
PULONG ReturnLength | |
); | |
extern "C" LONG NtQuerySystemInformation( | |
SYSTEM_INFORMATION_CLASS SystemInformationClass, | |
PVOID SystemInformation, | |
ULONG SystemInformationLength, | |
PULONG ReturnLength | |
); | |
struct VM_COUNTERS { | |
SIZE_T PeakVirtualSize; | |
SIZE_T VirtualSize; | |
ULONG PageFaultCount; | |
SIZE_T PeakWorkingSetSize; | |
SIZE_T WorkingSetSize; | |
SIZE_T QuotaPeakPagedPoolUsage; | |
SIZE_T QuotaPagedPoolUsage; | |
SIZE_T QuotaPeakNonPagedPoolUsage; | |
SIZE_T QuotaNonPagedPoolUsage; | |
SIZE_T PagefileUsage; | |
SIZE_T PeakPagefileUsage; | |
}; | |
struct MEMORY_USAGE_INFO { | |
SIZE_T PhysicalTotal; | |
SIZE_T PhysicalAvailable; | |
SIZE_T Field2; | |
SIZE_T CommitTotal; | |
SIZE_T Field4; | |
SIZE_T CommitLimit; | |
SIZE_T CommitPeak; | |
}; | |
int wmain(int argc, wchar_t* argv[]) { | |
PDH_HQUERY query; | |
PDH_STATUS status = ::PdhOpenQueryW(nullptr, 0, &query); | |
if (status != ERROR_SUCCESS) { | |
Log(L"PdhOpenQueryW failed - %08lx\n", status); | |
return false; | |
} | |
PDH_HCOUNTER perfCounterUsed, perfCounterTotal; | |
status = ::PdhAddCounterW( | |
query, L"\\Memory\\Committed Bytes", 0, &perfCounterUsed); | |
if (status != ERROR_SUCCESS) { | |
Log(L"PdhAddCounterW failed - %08lx\n", status); | |
return false; | |
} | |
status = ::PdhAddCounterW( | |
query, L"\\Memory\\Commit Limit", 0, &perfCounterTotal); | |
if (status != ERROR_SUCCESS) { | |
Log(L"PdhAddCounterW failed - %08lx\n", status); | |
return false; | |
} | |
QPC t; | |
for (;;) { | |
MEMORYSTATUSEX mse = {sizeof(mse)}; | |
t.Reset(); | |
if (::GlobalMemoryStatusEx(&mse)) { | |
Log(L"GMSE: %lld / %lld (%d)\n", | |
mse.ullAvailPageFile, | |
mse.ullTotalPageFile, | |
t.Tick()); | |
} | |
PERFORMANCE_INFORMATION pi; | |
t.Reset(); | |
if (::GetPerformanceInfo(&pi, sizeof(pi))) { | |
Log(L"GPI: %lld / %lld (%d)\n", | |
(pi.CommitLimit - pi.CommitTotal) * pi.PageSize, | |
pi.CommitLimit * pi.PageSize, | |
t.Tick()); | |
} | |
DWORD counterType1, counterType2; | |
PDH_RAW_COUNTER perfData1, perfData2; | |
t.Reset(); | |
if (::PdhCollectQueryData(query) == ERROR_SUCCESS | |
&& ::PdhGetRawCounterValue(perfCounterUsed, | |
&counterType1, | |
&perfData1) == ERROR_SUCCESS | |
&& ::PdhGetRawCounterValue(perfCounterTotal, | |
&counterType2, | |
&perfData2) == ERROR_SUCCESS | |
&& (counterType1 & PDH_FMT_LONG) | |
&& (counterType2 & PDH_FMT_LONG) | |
&& perfData1.CStatus == PDH_CSTATUS_VALID_DATA | |
&& perfData2.CStatus == PDH_CSTATUS_VALID_DATA) { | |
Log(L"PDH: %lld / %lld (%d)\n", | |
perfData2.FirstValue - perfData1.FirstValue, | |
perfData2.FirstValue, | |
t.Tick()); | |
} | |
DWORD len; | |
MEMORY_USAGE_INFO mui; | |
t.Reset(); | |
if (::NtQuerySystemInformation( | |
SystemMemoryUsageInformation, | |
&mui, sizeof(mui), &len) == ERROR_SUCCESS) { | |
Log(L"NQSI: %lld / %lld (%d)\n", | |
mui.CommitLimit - mui.CommitTotal, | |
mui.CommitLimit, | |
t.Tick()); | |
} | |
putchar('\n'); | |
::Sleep(1000); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment