locked
CPU and Memory Monitoring in Windows Mobile RRS feed

  • Question

  • Hi,

    I am trying to deevelop a simple Task Manager for Windows Mobile on my own using C++. I am not sure on how to get the following information:
    1) Total CPU usage
    2) Per process CPU and Memory usage.
    3) Total memory usage.

    For the third point I have been able to get an API, GlobalMemoryStatus. From that I can get the memory usage percentage from the memory load parameter.

    Can someone provide any guideline on how to get the first two using C++ code.

    Thank you,
    CED
    Wednesday, June 24, 2009 7:46 AM

Answers

  • You will need those:

    [DllImport("toolhelp.dll")]
    private static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
                                             
    [DllImport("toolhelp.dll")]
    private static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
    [DllImport("toolhelp.dll")]
    private static extern bool Module32First(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Module32Next(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32ListFirst(IntPtr hSnapshot, ref HEAPLIST32 lphl);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32ListNext(IntPtr hSnapshot, ref HEAPLIST32 lphl);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32First(IntPtr hSnapshot, ref HEAPENTRY32 lphe, uint th32ProcessID, uint th32HeapID);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32Next(IntPtr hSnapshot, ref HEAPENTRY32 lphe);
    
    [DllImport("toolhelp.dll", SetLastError = true)]
    private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
    
    [DllImport("toolhelp.dll", SetLastError = true)]
    private static extern bool CloseToolhelp32Snapshot(IntPtr hSnapshot);
    
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern bool GetThreadTimes(IntPtr hThread, ref ulong lpCreationTime, ref ulong lpExitTime, ref ulong lpKernelTime, ref ulong lpUserTime);

    It's for C# developement, but I don't think it will be a problem (just look for those methods in MSDN Library Documentation). You need to create a snapshot with flags for needed info.

    As for creating CPU usage - You need to create a process (actually a thread) called SystemIdleProcess with the lowest possible priority and get the time it is processed. It is processed as last so the process that is fist and takes longer time - produces greater CPU usage. If nothing is used at this time, SystemIdleProcess will get 99% of the whole time.

    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    • Proposed as answer by Mal Loth Wednesday, June 24, 2009 1:36 PM
    • Marked as answer by Guang-Ming Bian - MSFT Tuesday, June 30, 2009 2:32 AM
    • Unmarked as answer by C.E.D Tuesday, June 30, 2009 8:34 AM
    • Unproposed as answer by C.E.D Tuesday, June 30, 2009 8:35 AM
    • Marked as answer by C.E.D Tuesday, July 7, 2009 11:19 AM
    Wednesday, June 24, 2009 1:36 PM
  • Hi,

    I am using this code to monitor the usage of my task manager application. The value that it is returning it sometimes same or sometime higher than another standard task manager.

    BOOL GetPerProcessCpuUsage()
    {
    	int  processIndex = 0;
    	int  processCount = 0;
    	UINT count = 0;
    	PROCESSENTRY32 pe32;
    	THREADENTRY32 te32;
    
    	FILETIME ftKernelTime;
    	FILETIME ftUserTime;
    	FILETIME ftCreationTime;
    	FILETIME ftExitTime;
    
        LastThreadTime = 0;
        dwCurrentThreadTime =0;
        dwCurrentTickTime = 0;
        dwCpuPower=0;
    
    	 dwCurrentTickTime = GetTickCount();
    
    	 //Create the snapshot
    	 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);
    
    	 //Get the process list
    	 pe32.dwSize = sizeof(PROCESSENTRY32);
    	 te32.dwSize = sizeof(THREADENTRY32);
    
    	 DWORD orgPermissions = GetCurrentPermissions();
    	 DWORD ProcPermission = SetProcPermissions(0xFFFFFFFF);
    
    	 BOOL bReturn;
    	 if (true == Process32First(hSnapshot, &pe32)) 
    	 {
    		 //Iterate the process list
    		 do
    		 {
    			 dwCurrentThreadTime=0;
    			 //Iterate the threads
    			 if (Thread32First(hSnapshot, &te32))
    			 {
    				 do
    				 {
    					 //Calculate the information for the process in view
    					 if (te32.th32OwnerProcessID == pe32.th32ProcessID)
    					 {
    						 bReturn = GetThreadTimes((HANDLE)te32.th32ThreadID,
    											&ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);
    
                             dwCurrentThreadTime += GetThreadTick(&ftKernelTime, &ftUserTime);
                             count++;
    					 }
    				 } while (Thread32Next(hSnapshot, &te32));
    
    				 count = 0;
    
    				 // Go through the array to find a point to insert/modify the lastThreadtime of current process
    				  if ( (! _tcscmp(pe32.szExeFile,TEXT("TaskBoy.exe"))))
    				  {
    					  for (int i = 0;i<255;i++)
    					  {
    						  if (dwLastThreadTime[i][0] != 0)
    						  {
    							  // check if it has the same processID
    							  if ( dwLastThreadTime[i][0] == pe32.th32ProcessID )
    							  {
    								  LastThreadTime = dwLastThreadTime[i][1];
    								  dwLastThreadTime[i][1] = dwCurrentThreadTime;
    								  PPCP[processCount].PID = pe32.th32ProcessID;
    							  }
    							  else
    							  {
    								  continue;
    							  }
    						  }
    						  else
    						  {
    							  if (dwLastThreadTime[processIndex][0] != pe32.th32ProcessID)
    							  {
    								  LastThreadTime = 0.0;
    							  }
    							  dwLastThreadTime[processIndex][0] = pe32.th32ProcessID;
    							  PPCP[processCount].PID = pe32.th32ProcessID;
    							  dwLastThreadTime[processIndex++][1] = dwCurrentThreadTime;
    							  break ;
    						  }
    					  }
    					  if ( dwCurrentTickTime != dwLastTickTime &&   LastThreadTime != 0 && dwLastTickTime != 0 && dwCurrentThreadTime != LastThreadTime)
    					  {
    						  dwCpuPower = 100-(((dwCurrentThreadTime - LastThreadTime)*100) / (dwCurrentTickTime - dwLastTickTime));
    						  PPCP[processCount].CpuUsage = dwCpuPower;
    					  }
    					  else
    					  {
    						  //Avoid division by 0
    						  dwCpuPower = 0;
    					  }
    				  }
    			 }
    		 } while (Process32Next(hSnapshot, &pe32));
    		 dwLastTickTime = GetTickCount();
    	 }
    	 else
    	 {
    		 DWORD LastError = GetLastError();
    		 //Process not found
    		 if (hSnapshot!=NULL)
    			 CloseToolhelp32Snapshot(hSnapshot);
    		 return FALSE;
    	 }
    
    	ProcPermission = SetProcPermissions(orgPermissions);
    
    	CloseToolhelp32Snapshot(hSnapshot);
    	return TRUE;
    }

    Moreover, my application shows, it consumes, say for example 25%  then the other task manager is showing 15% and Windows default task manager is showing way higher, 50+. I am really puzzled, please help.

    Thank you,
    CED
    • Marked as answer by C.E.D Tuesday, July 7, 2009 11:20 AM
    Thursday, June 25, 2009 12:22 PM

All replies

  • Hi,

    There is a itsutils tools collection located at http://wiki.xda-developers.com/index.php?pagename=XdaUtils
    In this collection there is a pps tool. It prints what you need.
    You can look through source code http://nah6.com/~itsme/cvs-xdadevtools/itsutils/ how the tool implements it.
    Wednesday, June 24, 2009 12:32 PM
  • You will need those:

    [DllImport("toolhelp.dll")]
    private static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
                                             
    [DllImport("toolhelp.dll")]
    private static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
    [DllImport("toolhelp.dll")]
    private static extern bool Module32First(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Module32Next(IntPtr hSnapshot, ref MODULEENTRY32 lpme);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32ListFirst(IntPtr hSnapshot, ref HEAPLIST32 lphl);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32ListNext(IntPtr hSnapshot, ref HEAPLIST32 lphl);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32First(IntPtr hSnapshot, ref HEAPENTRY32 lphe, uint th32ProcessID, uint th32HeapID);
    
    [DllImport("toolhelp.dll")]
    private static extern bool Heap32Next(IntPtr hSnapshot, ref HEAPENTRY32 lphe);
    
    [DllImport("toolhelp.dll", SetLastError = true)]
    private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
    
    [DllImport("toolhelp.dll", SetLastError = true)]
    private static extern bool CloseToolhelp32Snapshot(IntPtr hSnapshot);
    
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);
    
    [DllImport("coredll.dll", SetLastError = true)]
    private static extern bool GetThreadTimes(IntPtr hThread, ref ulong lpCreationTime, ref ulong lpExitTime, ref ulong lpKernelTime, ref ulong lpUserTime);

    It's for C# developement, but I don't think it will be a problem (just look for those methods in MSDN Library Documentation). You need to create a snapshot with flags for needed info.

    As for creating CPU usage - You need to create a process (actually a thread) called SystemIdleProcess with the lowest possible priority and get the time it is processed. It is processed as last so the process that is fist and takes longer time - produces greater CPU usage. If nothing is used at this time, SystemIdleProcess will get 99% of the whole time.

    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    • Proposed as answer by Mal Loth Wednesday, June 24, 2009 1:36 PM
    • Marked as answer by Guang-Ming Bian - MSFT Tuesday, June 30, 2009 2:32 AM
    • Unmarked as answer by C.E.D Tuesday, June 30, 2009 8:34 AM
    • Unproposed as answer by C.E.D Tuesday, June 30, 2009 8:35 AM
    • Marked as answer by C.E.D Tuesday, July 7, 2009 11:19 AM
    Wednesday, June 24, 2009 1:36 PM
  • Hi ten0s,

    Thank you, for the links. I will go through the links. Now just need information regarding point #2 as I have archived to calculate the global memory and cpu usage.

    Thank you,
    CED
    Wednesday, June 24, 2009 4:16 PM
  • Hi Mal,

    I also found a topic similar to your thinking. I am in the process of implementing it. Hope it works. If so, then I will post the code in here so that other can take advantage of it.

    Thank you,
    CED
    Wednesday, June 24, 2009 4:17 PM
  • Done simillar thing in C#. But there were problems with this API.
    For some processes it shows bad memory mesurements (RAM calculations don't match), and it required to refresh from time to time the snapshot which took a lot of CPU cycles and probably also showed bad mesurements.
    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    Wednesday, June 24, 2009 6:41 PM
  • Hi,

    I am using this code to monitor the usage of my task manager application. The value that it is returning it sometimes same or sometime higher than another standard task manager.

    BOOL GetPerProcessCpuUsage()
    {
    	int  processIndex = 0;
    	int  processCount = 0;
    	UINT count = 0;
    	PROCESSENTRY32 pe32;
    	THREADENTRY32 te32;
    
    	FILETIME ftKernelTime;
    	FILETIME ftUserTime;
    	FILETIME ftCreationTime;
    	FILETIME ftExitTime;
    
        LastThreadTime = 0;
        dwCurrentThreadTime =0;
        dwCurrentTickTime = 0;
        dwCpuPower=0;
    
    	 dwCurrentTickTime = GetTickCount();
    
    	 //Create the snapshot
    	 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);
    
    	 //Get the process list
    	 pe32.dwSize = sizeof(PROCESSENTRY32);
    	 te32.dwSize = sizeof(THREADENTRY32);
    
    	 DWORD orgPermissions = GetCurrentPermissions();
    	 DWORD ProcPermission = SetProcPermissions(0xFFFFFFFF);
    
    	 BOOL bReturn;
    	 if (true == Process32First(hSnapshot, &pe32)) 
    	 {
    		 //Iterate the process list
    		 do
    		 {
    			 dwCurrentThreadTime=0;
    			 //Iterate the threads
    			 if (Thread32First(hSnapshot, &te32))
    			 {
    				 do
    				 {
    					 //Calculate the information for the process in view
    					 if (te32.th32OwnerProcessID == pe32.th32ProcessID)
    					 {
    						 bReturn = GetThreadTimes((HANDLE)te32.th32ThreadID,
    											&ftCreationTime, &ftExitTime, &ftKernelTime, &ftUserTime);
    
                             dwCurrentThreadTime += GetThreadTick(&ftKernelTime, &ftUserTime);
                             count++;
    					 }
    				 } while (Thread32Next(hSnapshot, &te32));
    
    				 count = 0;
    
    				 // Go through the array to find a point to insert/modify the lastThreadtime of current process
    				  if ( (! _tcscmp(pe32.szExeFile,TEXT("TaskBoy.exe"))))
    				  {
    					  for (int i = 0;i<255;i++)
    					  {
    						  if (dwLastThreadTime[i][0] != 0)
    						  {
    							  // check if it has the same processID
    							  if ( dwLastThreadTime[i][0] == pe32.th32ProcessID )
    							  {
    								  LastThreadTime = dwLastThreadTime[i][1];
    								  dwLastThreadTime[i][1] = dwCurrentThreadTime;
    								  PPCP[processCount].PID = pe32.th32ProcessID;
    							  }
    							  else
    							  {
    								  continue;
    							  }
    						  }
    						  else
    						  {
    							  if (dwLastThreadTime[processIndex][0] != pe32.th32ProcessID)
    							  {
    								  LastThreadTime = 0.0;
    							  }
    							  dwLastThreadTime[processIndex][0] = pe32.th32ProcessID;
    							  PPCP[processCount].PID = pe32.th32ProcessID;
    							  dwLastThreadTime[processIndex++][1] = dwCurrentThreadTime;
    							  break ;
    						  }
    					  }
    					  if ( dwCurrentTickTime != dwLastTickTime &&   LastThreadTime != 0 && dwLastTickTime != 0 && dwCurrentThreadTime != LastThreadTime)
    					  {
    						  dwCpuPower = 100-(((dwCurrentThreadTime - LastThreadTime)*100) / (dwCurrentTickTime - dwLastTickTime));
    						  PPCP[processCount].CpuUsage = dwCpuPower;
    					  }
    					  else
    					  {
    						  //Avoid division by 0
    						  dwCpuPower = 0;
    					  }
    				  }
    			 }
    		 } while (Process32Next(hSnapshot, &pe32));
    		 dwLastTickTime = GetTickCount();
    	 }
    	 else
    	 {
    		 DWORD LastError = GetLastError();
    		 //Process not found
    		 if (hSnapshot!=NULL)
    			 CloseToolhelp32Snapshot(hSnapshot);
    		 return FALSE;
    	 }
    
    	ProcPermission = SetProcPermissions(orgPermissions);
    
    	CloseToolhelp32Snapshot(hSnapshot);
    	return TRUE;
    }

    Moreover, my application shows, it consumes, say for example 25%  then the other task manager is showing 15% and Windows default task manager is showing way higher, 50+. I am really puzzled, please help.

    Thank you,
    CED
    • Marked as answer by C.E.D Tuesday, July 7, 2009 11:20 AM
    Thursday, June 25, 2009 12:22 PM
  • This seem to take much CPU time:
    CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);

    It's because You're taking snapshot of everything: HEAPS, THREADS, MEMORY etc.
    Use only what You need and You'll use lower CPU cycles for such a task.
    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    Thursday, June 25, 2009 8:12 PM
  • Thank you, for the reply Mal. I will be going through the procedure u said. Another probleam found is that, when I start an application, which has nothing but a while(1) loop in it, the above code sometimes show cpu usage more than 100%. What do you think the issue can be.

    Another issue we found while calculating per process memory usage is that this code returns much lower value than the value returned by Windows Mobile default Task Manager:

    BOOL GetPerProcessMemUsage()
    {
    	UINT MemUsage = 0;
    	HANDLE hSnapShot = NULL;
    	hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);
    
    	PROCESSENTRY32 pe32;
    	pe32.dwSize = sizeof(PROCESSENTRY32);
    
    	DWORD orgPermissions = GetCurrentPermissions();
    	DWORD ProcPermission = SetProcPermissions(0xFFFFFFFF);
    
    	BOOL bReturn;
    	if (true == Process32First(hSnapShot, &pe32))
    	{
    		do
    		{
    			if(!_tcscmp(pe32.szExeFile,TEXT("TaskBoy.exe")))
    			{
    				HEAPLIST32 hl32;
    				hl32.dwSize = sizeof(HEAPLIST32);
    				if(Heap32ListFirst(hSnapShot,&hl32))
    				{
    					do
    					{
    						HEAPENTRY32 he32;
    						he32.dwSize = sizeof(HEAPENTRY32);
    						if (Heap32First(hSnapShot,&he32,hl32.th32ProcessID,hl32.th32HeapID))
    						{
    							do
    							{
    								if ( hl32.th32ProcessID == pe32.th32ProcessID )
    								{
    									MemUsage += he32.dwBlockSize;
    									PPMP[0].MemoryUsed = MemUsage;
     } } while (Heap32Next(hSnapShot, &he32)); } } while (Heap32ListNext(hSnapShot, &hl32)); } DWORD Error = GetLastError(); Error++; } }while (Process32Next(hSnapShot, &pe32)); } else { DWORD dwLastError = GetLastError(); return FALSE; } ProcPermission = SetProcPermissions(orgPermissions); CloseToolhelp32Snapshot(hSnapShot); return TRUE; }
    • Edited by C.E.D Friday, June 26, 2009 5:38 AM
    Friday, June 26, 2009 5:32 AM
  • Well this "while(1) loop" is a nasty solution. If You're using this code inside a non-windowed app or service just use:

    MSG msg;
    
    while(GetMessage(&msg, 0, 0, 0))
    {
    	TranslateMessage(&msg);
    	DispatchMessage(&msg);
    }

    This won't allow Your service or background app to exit and return and is much lighter for asm code.
    Loops shouldn't be used with hard CPU loaders, like CreateToolhelp32Snapshot method.

    More preffered solution is to create a timer which will each 5-10sec get a new snapshot and refresh the on-screen data.

    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    Friday, June 26, 2009 8:38 AM
  • Hi,

    This is some sort of information required regarding the memory usage. When I run my code my traversing the heap using toolhelp32 APIs for an exe say Sample.exe, it gives me the result 7.9KB. The same value is also shown by one of the task manager tool, HandySwitcher, but for the same exe Windows default task manager shows it as 88KB.

    Can someone tell as to why there is such a huge gap and as to how Windows default task manager calculates proces memory which my application or commercial applications like HandySwitcher cannot show.

    Thank you,
    CED
    Friday, June 26, 2009 4:00 PM
  • Hi,

    To find the memory used by an application in Windows Mobile you need to use the following call, CeGetProcVMInfo. This is an undocumented call and can be found in pkfuncs.h. The values returned by them match with the values that are shown by the Windows default Task Manager.

    Thanks to Mal to give me the initial information to start. I now have a complete Task Manager class which can be used by any application to get system information:
    1. Overall cpu usage & memory usage
    2. Per process cpu & memory usage

    Thank you,
    CED
    Tuesday, July 7, 2009 11:24 AM
  • No problem. Major work You did all by Yourself - congratulations :).
    I wonder when will that function become 'official'.

    If You'll find my answer satisfactory or helpful - mark it as answered! Thank You. PS. Votes also doesn't hurt :).
    Tuesday, July 7, 2009 8:08 PM
  • Hi CED,

    I was going thru this mail chain and found that you have exactly for something I am looking for. I have a windows CE based application developed and I need to measure CPU usage, memory usage of my application. Windows Task Manager seems to be giving way too high numbers which I dont seem to trust.

    can you pl. recommend me some tool or as you mentioned that you plan to post your tool/code do you have one which can help me check on my application CPU and memory usage?

     

    Thanks,

    VGS

    Saturday, June 25, 2011 1:37 PM