The aim of this example is to create a simple program that will display CPU and memory uisng PDH Performance Counters. We will be using the windows command line compiler cl.exe that comes with Visual Studio C++ for this example. Leave any questions or problems as comments and I will endeavour to answer them.
Assumptions
This article assumes that you have VC++ installed and configured. See Problems and Solutions Installing VC++ Express Edition, to install and run vcvars32.bat.
Versions used in this example
| Sofware/Component | Image |
| Windows XP SP2 | N/A |
| Visual Studio Express Editions 2008 VC++ | N/A |
Write and compile the application
- While you can get Memory status fairly easlily with GlobalMemoryStatusEx, there is no equivalent function for CPU. Therefore you have to use PDH Performance Counter Interface to get CPU utilisation. Write the application and save is as check.cpp.
Also note that CPU is a difference between two PdhCollectQueryData calls, so if you call this once and try to get PdhGetFormattedCounterValue you will get an error.
1. #include <iostream> 2. #include <windows.h> 3. #include <stdio.h> 4. #include <pdh.h> 5. #include <pdhmsg.h> 6. 7. #define KB 1024 8. void main(int argc, char *argv[]){ 9. 10. PDH_HQUERY hquery; 11. PDH_HCOUNTER hcountercpu; 12. PDH_HCOUNTER hcounterram; 13. PDH_STATUS status; 14. LPSTR pMessage; 15. PDH_FMT_COUNTERVALUE countervalcpu; 16. PDH_FMT_COUNTERVALUE countervalram; 17. MEMORYSTATUSEX memstat; 18. 19. memstat.dwLength = sizeof (memstat); 20. 21. if((status=PdhOpenQuery(NULL, 0, &hquery))!=ERROR_SUCCESS){ 22. printf("PdhOpenQuery %lx\n", status); 23. goto END; 24. } 25. 26. if((status=PdhAddCounter(hquery, 27. "\\Processor(_Total)\\% Processor Time", 28. 0, 29. &hcountercpu))!=ERROR_SUCCESS){ 30. printf("PdhAddCounter (cpu) %lx\n", status); 31. goto END; 32. } 33. if((status=PdhAddCounter(hquery, 34. "\\Memory\\Available Bytes", 35. 0, 36. &hcounterram))!=ERROR_SUCCESS){ 37. printf("PdhAddCounter (ram) %lx\n", status); 38. goto END; 39. } 40. 41. /*Start outside the loop as CPU requires difference 42. between two PdhCollectQueryData s*/ 43. if((status=PdhCollectQueryData(hquery))!=ERROR_SUCCESS){ 44. printf("PdhCollectQueryData %lx\n", status); 45. goto END; 46. } 47. 48. while(true){ 49. 50. if((status=PdhCollectQueryData(hquery))!=ERROR_SUCCESS){ 51. printf("PdhCollectQueryData %lx\n", status); 52. goto END; 53. } 54. if(GlobalMemoryStatusEx(&memstat)==0){ 55. printf("GlobalMemoryStatusEx %d\n", GetLastError()); 56. goto END; 57. } 58. 59. if((status=PdhGetFormattedCounterValue(hcountercpu, 60. PDH_FMT_LONG, 61. 0, 62. &countervalcpu))!=ERROR_SUCCESS){ 63. printf("PdhGetFormattedCounterValue(cpu) %lx\n", status); 64. goto END; 65. } 66. if((status=PdhGetFormattedCounterValue(hcounterram, 67. PDH_FMT_LONG, 68. 0, 69. &countervalram))!=ERROR_SUCCESS){ 70. printf("PdhGetFormattedCounterValue(ram) %lx\n", status); 71. goto END; 72. } 73. printf("cpu %3d%% \tmem %3d%% \tavail (%d mb)\n", 74. countervalcpu.longValue, 75. memstat.dwMemoryLoad, 76. countervalram.longValue/(KB*KB)); 77. 78. Sleep(1000); 79. 80. } 81. END: 82. ; 83. }
- Open a prompt to the working directory and compile the code using the windows cl.exe compiler. You just need to include the pdh.lib.
..workspace\PerfCounter>cl check.cpp pdf.lib
- Now run the program in the command prompt. You should see the cpu and memory snapshot displayed every second.
