Bug of performance counter API or perfmon tool
-
Hello everyone, I found using performance counter API and using perfmon counter will result in different numeric result. Here is an example, and in the example code, virtual bytes is always larger than working set, but in perfmon, working set is always larger than working set. Any ideas?
#include #include #include #include #pragma comment(lib, "pdh") PDH_STATUS ps; CHAR wsPath[256]; CHAR vbPath[256]; DWORD wsItems = 0; DWORD wsSize = 0; DWORD vbItems = 0; DWORD vbSize = 0; FILE* fLog = fopen("perfcount.log", "w+"); CHAR processModule[MAX_PATH] = {0}; CHAR* GetProcModuleName() { if (GetModuleFileName(GetModuleHandle(NULL), processModule, sizeof(processModule))) { CHAR* p = strrchr(processModule, '.'); if (p) *p = '\0'; else return NULL; p = strrchr(processModule, '\\'); if (p) return (p + 1); } return NULL; } void GetCounters(DWORD sectionIndex) { HQUERY hQuery; HCOUNTER hWsCount; HCOUNTER hVbCount; ps = PdhOpenQuery(NULL, 0, &hQuery); ps = PdhAddCounter(hQuery, wsPath, 0, &hWsCount); ps = PdhAddCounter(hQuery, vbPath, 0, &hVbCount); ps = PdhCollectQueryData(hQuery); wsItems = 0; wsSize = 0; vbItems = 0; vbSize = 0; PDH_RAW_COUNTER_ITEM* pWS = NULL; PDH_RAW_COUNTER_ITEM* pVB = NULL; ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, NULL); pWS = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, wsSize); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, NULL); pVB = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, vbSize); ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, pWS); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, pVB); ps = PdhCloseQuery(hQuery); CTime t = pWS->RawValue.TimeStamp; fprintf(fLog, "[%s] SI: %6d\t WS: %.2f Mb\tVB: %.2f Mb\n", t.Format("%c"), sectionIndex, double(pWS->RawValue.FirstValue) /1024 /1024, double(pVB->RawValue.FirstValue) /1024 /1024); LocalFree(pWS); LocalFree(pVB); fflush(fLog); } int main(int argc, char* argv[]) { LARGE_INTEGER start,end; LARGE_INTEGER freq; QueryPerformanceCounter(&start); QueryPerformanceFrequency(&freq); MEMORYSTATUS memstat; void** map; int sectionIndex = 0; memstat.dwLength = sizeof(memstat); GlobalMemoryStatus(&memstat); // basic file mapping test (512 MB) long long size = 512*1024*1024; DWORD nsize = 0; CHAR poName[256]; CHAR wsName[256]; CHAR vbName[256]; nsize = size
-
Hello everyone, I found using performance counter API and using perfmon counter will result in different numeric result. Here is an example, and in the example code, virtual bytes is always larger than working set, but in perfmon, working set is always larger than working set. Any ideas?
#include #include #include #include #pragma comment(lib, "pdh") PDH_STATUS ps; CHAR wsPath[256]; CHAR vbPath[256]; DWORD wsItems = 0; DWORD wsSize = 0; DWORD vbItems = 0; DWORD vbSize = 0; FILE* fLog = fopen("perfcount.log", "w+"); CHAR processModule[MAX_PATH] = {0}; CHAR* GetProcModuleName() { if (GetModuleFileName(GetModuleHandle(NULL), processModule, sizeof(processModule))) { CHAR* p = strrchr(processModule, '.'); if (p) *p = '\0'; else return NULL; p = strrchr(processModule, '\\'); if (p) return (p + 1); } return NULL; } void GetCounters(DWORD sectionIndex) { HQUERY hQuery; HCOUNTER hWsCount; HCOUNTER hVbCount; ps = PdhOpenQuery(NULL, 0, &hQuery); ps = PdhAddCounter(hQuery, wsPath, 0, &hWsCount); ps = PdhAddCounter(hQuery, vbPath, 0, &hVbCount); ps = PdhCollectQueryData(hQuery); wsItems = 0; wsSize = 0; vbItems = 0; vbSize = 0; PDH_RAW_COUNTER_ITEM* pWS = NULL; PDH_RAW_COUNTER_ITEM* pVB = NULL; ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, NULL); pWS = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, wsSize); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, NULL); pVB = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, vbSize); ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, pWS); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, pVB); ps = PdhCloseQuery(hQuery); CTime t = pWS->RawValue.TimeStamp; fprintf(fLog, "[%s] SI: %6d\t WS: %.2f Mb\tVB: %.2f Mb\n", t.Format("%c"), sectionIndex, double(pWS->RawValue.FirstValue) /1024 /1024, double(pVB->RawValue.FirstValue) /1024 /1024); LocalFree(pWS); LocalFree(pVB); fflush(fLog); } int main(int argc, char* argv[]) { LARGE_INTEGER start,end; LARGE_INTEGER freq; QueryPerformanceCounter(&start); QueryPerformanceFrequency(&freq); MEMORYSTATUS memstat; void** map; int sectionIndex = 0; memstat.dwLength = sizeof(memstat); GlobalMemoryStatus(&memstat); // basic file mapping test (512 MB) long long size = 512*1024*1024; DWORD nsize = 0; CHAR poName[256]; CHAR wsName[256]; CHAR vbName[256]; nsize = size
-
Hi Don, Sorry that I have not found the function to attach source file, so I post the source code here. The reproduce of this issue is quite easy, 1. Build the code and run; 2. At the same time, using perfmon tool to monitor the working set and virtual bytes counter; 3. When running compelte, check the content in file perfcount.log. In Perfmon tool, you can always find working set is larger than virtual bytes; In the perfcount.log, you can always find virtual bytes is larger than working set. If you either could tell me how to attach a file into the forum or tell me your email address, I can send you the code so that you can build and reproduce very easily. regards, George
-
Hello everyone, I found using performance counter API and using perfmon counter will result in different numeric result. Here is an example, and in the example code, virtual bytes is always larger than working set, but in perfmon, working set is always larger than working set. Any ideas?
#include #include #include #include #pragma comment(lib, "pdh") PDH_STATUS ps; CHAR wsPath[256]; CHAR vbPath[256]; DWORD wsItems = 0; DWORD wsSize = 0; DWORD vbItems = 0; DWORD vbSize = 0; FILE* fLog = fopen("perfcount.log", "w+"); CHAR processModule[MAX_PATH] = {0}; CHAR* GetProcModuleName() { if (GetModuleFileName(GetModuleHandle(NULL), processModule, sizeof(processModule))) { CHAR* p = strrchr(processModule, '.'); if (p) *p = '\0'; else return NULL; p = strrchr(processModule, '\\'); if (p) return (p + 1); } return NULL; } void GetCounters(DWORD sectionIndex) { HQUERY hQuery; HCOUNTER hWsCount; HCOUNTER hVbCount; ps = PdhOpenQuery(NULL, 0, &hQuery); ps = PdhAddCounter(hQuery, wsPath, 0, &hWsCount); ps = PdhAddCounter(hQuery, vbPath, 0, &hVbCount); ps = PdhCollectQueryData(hQuery); wsItems = 0; wsSize = 0; vbItems = 0; vbSize = 0; PDH_RAW_COUNTER_ITEM* pWS = NULL; PDH_RAW_COUNTER_ITEM* pVB = NULL; ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, NULL); pWS = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, wsSize); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, NULL); pVB = (PDH_RAW_COUNTER_ITEM*)LocalAlloc(LPTR, vbSize); ps = PdhGetRawCounterArray(hWsCount, &wsSize, &wsItems, pWS); ps = PdhGetRawCounterArray(hVbCount, &vbSize, &vbItems, pVB); ps = PdhCloseQuery(hQuery); CTime t = pWS->RawValue.TimeStamp; fprintf(fLog, "[%s] SI: %6d\t WS: %.2f Mb\tVB: %.2f Mb\n", t.Format("%c"), sectionIndex, double(pWS->RawValue.FirstValue) /1024 /1024, double(pVB->RawValue.FirstValue) /1024 /1024); LocalFree(pWS); LocalFree(pVB); fflush(fLog); } int main(int argc, char* argv[]) { LARGE_INTEGER start,end; LARGE_INTEGER freq; QueryPerformanceCounter(&start); QueryPerformanceFrequency(&freq); MEMORYSTATUS memstat; void** map; int sectionIndex = 0; memstat.dwLength = sizeof(memstat); GlobalMemoryStatus(&memstat); // basic file mapping test (512 MB) long long size = 512*1024*1024; DWORD nsize = 0; CHAR poName[256]; CHAR wsName[256]; CHAR vbName[256]; nsize = size
George_George wrote:
...working set is always larger than working set.
Really? That would indeed indicate a problem.
"Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
-
George_George wrote:
...working set is always larger than working set.
Really? That would indeed indicate a problem.
"Normal is getting dressed in clothes that you buy for work and driving through traffic in a car that you are still paying for, in order to get to the job you need to pay for the clothes and the car and the house you leave vacant all day so you can afford to live in it." - Ellen Goodman
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
Hi DavidCrow, You can have a try and it is easy to reproduce. If you want to get the code directly to save time, I can send you code through email. I am not sure whether it is my mistake for the code and for the tool? So, it is appreciated if you could have a review. :-) regards, George