WebKitTools/record-memory-win/main.cpp
changeset 0 4f2f89ce4247
--- /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 <windows.h>
+#include <assert.h>
+#include <psapi.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <time.h>
+#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;
+}