Thread: Bug of performance counter API or perfmon tool

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    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?

    Code:
    #include <windows.h> 
    #include <stdio.h> 
    #include <pdh.h>
    #include <atltime.h>
    
    #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 = sizeof(poName);
    	ps = PdhLookupPerfNameByIndex(NULL, 230, poName, &nsize);  // Process object
    	nsize = sizeof(wsName);
    	ps = PdhLookupPerfNameByIndex(NULL, 180, wsName, &nsize);  // Working Set counter
    	nsize = sizeof(vbName);
    	ps = PdhLookupPerfNameByIndex(NULL, 174, vbName, &nsize);  // Virtual Bytes counter
    
    	PDH_COUNTER_PATH_ELEMENTS pcpe = {0};
    	pcpe.szObjectName = poName;
    	pcpe.szInstanceName = GetProcModuleName();
    	
    	pcpe.szCounterName = wsName;
    	nsize = sizeof(wsPath);
    	ps = PdhMakeCounterPath(&pcpe, wsPath, &nsize, 0);
    
    	pcpe.szCounterName = vbName;
    	nsize = sizeof(vbPath);
    	ps = PdhMakeCounterPath(&pcpe, vbPath, &nsize, 0);
    
    	HANDLE mapping = 
    	CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE|SEC_COMMIT,(DWORD)(size>>32),DWORD(size),NULL); 
    	if (mapping) 
    	{ 
    		// create and destroy temporary views 
    		SYSTEM_INFO sysInfo; 
    		GetSystemInfo(&sysInfo); 
    		const int allocSize = sysInfo.dwAllocationGranularity; 
    
    		GlobalMemoryStatus(&memstat); 
    
    		void *mem = new char[allocSize]; 
    		memset(mem,0x11,allocSize); 
    
    		map = (void**) new char [sizeof(void*) * size / allocSize];
    
    		for (int i=0; i<1; i++) 
    		{ 
    
    			sectionIndex = 0;
    			for (long long offset=0; offset<=size-allocSize; offset+=allocSize) 
    			{ 
    				map [sectionIndex] = 
    				MapViewOfFile(mapping,FILE_MAP_WRITE,(DWORD)(offset>>32),(DWORD)offset,allocSize); 
    				if (map [sectionIndex]) 
    				{ 
    					memcpy(map [sectionIndex],mem,allocSize); 
    
    					GetCounters(sectionIndex);
    
    					// UnmapViewOfFile(map);
    				}
    
    				sectionIndex++;
    			} // for (long long offset=0; offset<=size-allocSize; offset+=allocSize) 
    			
    			// close mapped files to avoid leak
    			for (sectionIndex = 0; sectionIndex < size/allocSize; sectionIndex++)
    			{
    				if (map [sectionIndex])
    				{ 
    					UnmapViewOfFile(map [sectionIndex]);
    				}
    			}
    
    			GlobalMemoryStatus(&memstat); 
    
    			sectionIndex = 0;
    			for (long long offset=0; offset<=size-allocSize; offset+=allocSize) 
    			{ 
    				map [sectionIndex] = 
    				MapViewOfFile(mapping,FILE_MAP_READ,(DWORD)(offset>>32),(DWORD)offset,allocSize); 
    				if (map [sectionIndex]) 
    				{ 
    					for (int t=0; t<allocSize; t++) 
    					{ 
    						if (((char *)(map [sectionIndex]))[t]!=0x11) 
    						{ 
    							OutputDebugString("Memory read failed\n"); 
    						} 
    					} 
    
    					GetCounters(sectionIndex);
    				} 
    
    				UnmapViewOfFile(map [sectionIndex]);
    				sectionIndex++;
    			} 
    
    			// close mapped files to avoid leak
    			/*
    			for (sectionIndex = 0; sectionIndex < size/allocSize; sectionIndex++)
    			{
    				if (map [sectionIndex])
    				{ 
    					UnmapViewOfFile(map [sectionIndex]);
    				}
    			}
    			*/
    
    			GlobalMemoryStatus(&memstat); 
    		} // for (int i=0; i<10; i++)
    
    		QueryPerformanceCounter(&end); 
    
    		GlobalMemoryStatus(&memstat); 
    
    		printf("Time %.3f\n", 
    		double(end.QuadPart-start.QuadPart)/double(freq.QuadPart)); 
    		CloseHandle(mapping); 
    		delete[] mem; 
    		GlobalMemoryStatus(&memstat); 
    	} //if (mapping)
    
    	fclose(fLog);
    
    	return 0;
    }

    thanks in advance,
    George

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Have you told Microsoft as well?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Hi Salem,


    I am not sure whether it is my sample bug or my limited knowledge or operation error on perfmon tool. So, I would like you and other people to reivew here. :-)

    Quote Originally Posted by Salem View Post
    Have you told Microsoft as well?

    regards,
    George

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Promblem with code
    By watchdogger in forum C Programming
    Replies: 18
    Last Post: 01-31-2009, 06:36 PM
  2. Scale in perfmon tool
    By George2 in forum Tech Board
    Replies: 0
    Last Post: 02-03-2008, 01:54 AM
  3. Page File counter and Private Bytes Counter
    By George2 in forum Tech Board
    Replies: 0
    Last Post: 01-31-2008, 03:17 AM
  4. Performance counter index
    By George2 in forum Windows Programming
    Replies: 4
    Last Post: 01-22-2008, 08:49 PM
  5. FILES in WinAPI
    By Garfield in forum Windows Programming
    Replies: 46
    Last Post: 10-02-2003, 06:51 PM