main.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include <windows.h>
  2. #include <assert.h>
  3. #include <psapi.h>
  4. #include <stdio.h>
  5. #include <tchar.h>
  6. #include <time.h>
  7. #include <tlhelp32.h>
  8. #include "Shlwapi.h"
  9. #pragma comment(lib, "psapi.lib")
  10. #pragma comment(lib, "shlwapi.lib")
  11. int gQueryInterval = 5; // seconds
  12. time_t gDuration = 0; // seconds
  13. LPTSTR gCommandLine;
  14. HRESULT ProcessArgs(int argc, TCHAR *argv[]);
  15. HRESULT PrintUsage();
  16. void UseImage(void (functionForQueryType(HANDLE)));
  17. void QueryContinuously(HANDLE hProcess);
  18. int EvalProcesses(HANDLE hProcess);
  19. time_t ElapsedTime(time_t startTime);
  20. int __cdecl _tmain (int argc, TCHAR *argv[])
  21. {
  22. HRESULT result = ProcessArgs(argc, argv);
  23. if (FAILED(result))
  24. return result;
  25. UseImage(QueryContinuously);
  26. return S_OK;
  27. }
  28. HRESULT ProcessArgs(int argc, TCHAR *argv[])
  29. {
  30. LPTSTR argument;
  31. for( int count = 1; count < argc; count++ ) {
  32. argument = argv[count] ;
  33. if (wcsstr(argument, _T("-h")) || wcsstr(argument, _T("--help")))
  34. return PrintUsage();
  35. else if (wcsstr(argument, _T("--exe"))) {
  36. gCommandLine = argv[++count];
  37. } else if (wcsstr(argument, _T("-i")) ||
  38. wcsstr(argument, _T("--interval"))) {
  39. gQueryInterval = _wtoi(argv[++count]);
  40. if (gQueryInterval < 1) {
  41. printf("ERROR: invalid interval\n");
  42. return E_INVALIDARG;
  43. }
  44. } else if (wcsstr(argument, _T("-d")) ||
  45. wcsstr(argument, _T("--duration"))) {
  46. gDuration = _wtoi(argv[++count]);
  47. if (gDuration < 1) {
  48. printf("ERROR: invalid duration\n");
  49. return E_INVALIDARG;
  50. }
  51. } else {
  52. _tprintf(_T("ERROR: unrecognized argument \"%s\"\n"), (LPCTSTR)argument);
  53. return PrintUsage();
  54. }
  55. }
  56. if (argc < 2 || !wcslen(gCommandLine) ) {
  57. printf("ERROR: executable path is required\n");
  58. return PrintUsage();
  59. }
  60. return S_OK;
  61. }
  62. HRESULT PrintUsage()
  63. {
  64. printf("record-memory-win --exe EXE_PATH\n");
  65. printf(" Launch an executable and print the memory usage (in Private Bytes)\n");
  66. printf(" of the process.\n\n");
  67. printf("Usage:\n");
  68. printf("-h [--help] : Print usage\n");
  69. printf("--exe arg : Launch specified image. Required\n");
  70. printf("-i [--interval] arg : Print memory usage every arg seconds. Default: 5 seconds\n");
  71. printf("-d [--duration] arg : Run for up to arg seconds. Default: no limit\n\n");
  72. printf("Examples:\n");
  73. printf(" record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe /newprocess\"\n");
  74. printf(" record-memory-win --exe \"Safari.exe /newprocess\" -i 10 -d 7200\n");
  75. printf(" NOTE: Close all other browser intances to ensure launching in a new process\n");
  76. printf(" Or, pass the /newprocess (or equivalent) argument to the browser\n");
  77. return E_FAIL;
  78. }
  79. unsigned int getMemoryInfo(DWORD processID)
  80. {
  81. unsigned int memInfo = 0;
  82. HANDLE hProcess;
  83. PROCESS_MEMORY_COUNTERS_EX pmc;
  84. hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
  85. PROCESS_VM_READ,
  86. FALSE, processID );
  87. if (NULL == hProcess)
  88. return 0;
  89. if (GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) {
  90. memInfo = (pmc.PrivateUsage);
  91. }
  92. CloseHandle( hProcess );
  93. return memInfo;
  94. }
  95. void printProcessInfo(DWORD processID)
  96. {
  97. TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
  98. // Get a handle to the process.
  99. HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
  100. PROCESS_VM_READ,
  101. FALSE, processID );
  102. // Get the process name.
  103. if (NULL != hProcess) {
  104. HMODULE hMod; // An array that receives the list of module handles.
  105. DWORD cbNeeded; //The number of bytes required to store all module handles in the Module array
  106. if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
  107. GetModuleBaseName(hProcess, hMod, szProcessName,
  108. sizeof(szProcessName)/sizeof(TCHAR));
  109. }
  110. }
  111. // Print the process name and identifier of matching strings, ignoring case
  112. _tprintf(TEXT("%s (PID: %u)\n"), szProcessName, processID);
  113. // Release the handle to the process.
  114. CloseHandle( hProcess );
  115. }
  116. int evalProcesses(HANDLE hProcess)
  117. {
  118. if (NULL == hProcess)
  119. return 0;
  120. unsigned int totalMemUsage = 0;
  121. DWORD processID = GetProcessId(hProcess);
  122. HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  123. PROCESSENTRY32 processEntry = { 0 };
  124. processEntry.dwSize = sizeof(PROCESSENTRY32);
  125. // Retrieves information about the first process encountered in a system snapshot
  126. if(Process32First(hProcessSnapshot, &processEntry)) {
  127. do {
  128. // if th32processID = processID, we are the parent process!
  129. // if th32ParentProcessID = processID, we are a child process!
  130. if ((processEntry.th32ProcessID == processID) || (processEntry.th32ParentProcessID == processID)) {
  131. unsigned int procMemUsage = 0;
  132. // Record parent process memory
  133. procMemUsage = getMemoryInfo(processEntry.th32ProcessID);
  134. totalMemUsage += procMemUsage;
  135. }
  136. // Retrieves information about the next process recorded in a system snapshot.
  137. } while(Process32Next(hProcessSnapshot, &processEntry));
  138. }
  139. CloseHandle(hProcessSnapshot);
  140. return totalMemUsage;
  141. }
  142. void UseImage(void (functionForQueryType(HANDLE)))
  143. {
  144. STARTUPINFO si = {0};
  145. si.cb = sizeof(STARTUPINFO);
  146. PROCESS_INFORMATION pi = {0};
  147. // Start the child process.
  148. if(!CreateProcess( NULL, // No module name (use command line)
  149. gCommandLine, // Command line
  150. NULL, // Process handle not inheritable
  151. NULL, // Thread handle not inheritable
  152. FALSE, // Set handle inheritance to FALSE
  153. 0, // No creation flags
  154. NULL, // Use parent's environment block
  155. NULL, // Use parent's starting directory
  156. &si, // Pointer to STARTUPINFO structure
  157. &pi )) // Pointer to PROCESS_INFORMATION structure
  158. printf("CreateProcess failed (%d)\n", GetLastError());
  159. else {
  160. printf("Created process with id: %d\n", pi.dwProcessId);
  161. functionForQueryType(pi.hProcess);
  162. // Close process and thread handles.
  163. CloseHandle( pi.hProcess );
  164. CloseHandle( pi.hThread );
  165. }
  166. }
  167. void QueryContinuously(HANDLE hProcess)
  168. {
  169. Sleep(2000); // give the process some time to launch
  170. bool pastDuration = false;
  171. time_t startTime = time(NULL);
  172. unsigned int memUsage = evalProcesses(hProcess);
  173. while(memUsage && !pastDuration) {
  174. printf( "%u\n", memUsage );
  175. Sleep(gQueryInterval*1000);
  176. memUsage = evalProcesses(hProcess);
  177. pastDuration = gDuration > 0 ? ElapsedTime(startTime) > gDuration : false;
  178. }
  179. }
  180. // returns elapsed time in seconds
  181. time_t ElapsedTime(time_t startTime)
  182. {
  183. time_t currentTime = time(NULL);
  184. return currentTime - startTime;
  185. }