diff -r 000000000000 -r 4f2f89ce4247 WebKitTools/record-memory-win/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKitTools/record-memory-win/main.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include "Shlwapi.h" + +#pragma comment(lib, "psapi.lib") +#pragma comment(lib, "shlwapi.lib") + +bool gSingleProcess = true; +int gQueryInterval = 5; // seconds +time_t gDuration = 0; // seconds +LPTSTR gCommandLine; + +HRESULT ProcessArgs(int argc, TCHAR *argv[]); +HRESULT PrintUsage(); +void UseImage(void (functionForQueryType(HANDLE))); +void QueryContinuously(HANDLE hProcess); +time_t ElapsedTime(time_t startTime); +unsigned int OneQuery(HANDLE hProcess); +unsigned int OneQueryMP(HANDLE hProcess); + +int __cdecl _tmain (int argc, TCHAR *argv[]) +{ + HRESULT result = ProcessArgs(argc, argv); + if (FAILED(result)) + return result; + + UseImage(QueryContinuously); + return S_OK; +} + +HRESULT ProcessArgs(int argc, TCHAR *argv[]) +{ + LPTSTR argument; + for( int count = 1; count < argc; count++ ) { + argument = argv[count] ; + if (wcsstr(argument, _T("-h")) || + wcsstr(argument, _T("--help"))) + return PrintUsage(); + else if (wcsstr(argument, _T("--exe"))) { + gCommandLine = argv[++count]; + if (wcsstr(gCommandLine, _T("chrome.exe"))) + gSingleProcess = false; + } else if (wcsstr(argument, _T("-i")) || + wcsstr(argument, _T("--interval"))) { + gQueryInterval = _wtoi(argv[++count]); + if (gQueryInterval < 1) { + printf("ERROR: invalid interval\n"); + return E_INVALIDARG; + } + } else if (wcsstr(argument, _T("-d")) || + wcsstr(argument, _T("--duration"))) { + gDuration = _wtoi(argv[++count]); + if (gDuration < 1) { + printf("ERROR: invalid duration\n"); + return E_INVALIDARG; + } + } else { + _tprintf(_T("ERROR: unrecognized argument \"%s\"\n"), (LPCTSTR)argument); + return PrintUsage(); + } + } + if (argc < 2 || !wcslen(gCommandLine) ) { + printf("ERROR: executable path is required\n"); + return PrintUsage(); + } + return S_OK; +} + +HRESULT PrintUsage() +{ + printf("record-memory-win --exe EXE_PATH\n"); + printf(" Launch an executable and print the memory usage (in Private Bytes)\n"); + printf(" of the process.\n\n"); + printf("Usage:\n"); + printf("-h [--help] : Print usage\n"); + printf("--exe arg : Launch specified image. Required\n"); + printf("-i [--interval] arg : Print memory usage every arg seconds. Default: 5 seconds\n"); + printf("-d [--duration] arg : Run for up to arg seconds. Default: no limit\n\n"); + printf("Examples:\n"); + printf(" record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe\"\n"); + printf(" record-memory-win --exe Safari.exe -i 10 -d 7200\n"); + return E_FAIL; +} + +void UseImage(void (functionForQueryType(HANDLE))) +{ + STARTUPINFO si = {0}; + si.cb = sizeof(STARTUPINFO); + PROCESS_INFORMATION pi = {0}; + + // Start the child process. + if(!CreateProcess( NULL, // No module name (use command line) + gCommandLine, // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // Set handle inheritance to FALSE + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &si, // Pointer to STARTUPINFO structure + &pi )) // Pointer to PROCESS_INFORMATION structure + printf("CreateProcess failed (%d)\n", GetLastError()); + else { + printf("Created process\n"); + functionForQueryType(pi.hProcess); + // Close process and thread handles. + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + } +} + +void QueryContinuously(HANDLE hProcess) +{ + Sleep(2000); // give the process some time to launch + bool pastDuration = false; + time_t startTime = time(NULL); + unsigned int memUsage = gSingleProcess ? OneQuery(hProcess) : OneQueryMP(hProcess); + while(memUsage && !pastDuration) { + printf( "%u\n", memUsage ); + Sleep(gQueryInterval*1000); + memUsage = gSingleProcess ? OneQuery(hProcess) : OneQueryMP(hProcess); + pastDuration = gDuration > 0 ? ElapsedTime(startTime) > gDuration : false; + } +} + +// returns elapsed time in seconds +time_t ElapsedTime(time_t startTime) +{ + time_t currentTime = time(NULL); + return currentTime - startTime; +} + +// returns Commit Size (Private Bytes) in bytes +unsigned int OneQuery(HANDLE hProcess) +{ + PROCESS_MEMORY_COUNTERS_EX pmc; + if (NULL == hProcess) + return 0; + if (GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) + return (unsigned)pmc.PrivateUsage; + return 0; +} + +// returns Commit Size (Private Bytes) in bytes for multi-process executables +unsigned int OneQueryMP(HANDLE hProcess) +{ + unsigned int memUsage = 0; + TCHAR monitoredProcessName[MAX_PATH]; + GetProcessImageFileName(hProcess, monitoredProcessName, sizeof(monitoredProcessName)/sizeof(TCHAR)); + LPTSTR shortProcessName = PathFindFileName(monitoredProcessName); + DWORD aProcesses[1024], cbNeeded, cProcesses; + HANDLE hFoundProcess; + if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) + return 0; + + // Calculate how many process identifiers were returned. + cProcesses = cbNeeded / sizeof(DWORD); + // find existing process + for (unsigned int i = 0; i < cProcesses; i++) + if (aProcesses[i] != 0) { + DWORD retVal = 0; + TCHAR foundProcessName[MAX_PATH]; + + // Get a handle to the process. + hFoundProcess = OpenProcess(PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ, + FALSE, aProcesses[i]); + + // Get the process name. + if (NULL != hFoundProcess) { + HMODULE hMod; + DWORD cbNeeded; + + if (EnumProcessModules(hFoundProcess, &hMod, sizeof(hMod), &cbNeeded)) { + GetModuleBaseName(hFoundProcess, hMod, foundProcessName, sizeof(foundProcessName)/sizeof(TCHAR)); + if (wcsstr(foundProcessName, shortProcessName)) + memUsage += OneQuery(hFoundProcess); + } + } + CloseHandle(hFoundProcess); + } + return memUsage; +}